home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #11 / Amiga Plus CD - 2002 - No. 11.iso / Games / WormWars / Source / engine.c < prev    next >
C/C++ Source or Header  |  2002-10-16  |  194KB  |  5,332 lines

  1. /* $Filename: WormWars/Source/engine.c
  2.  * $VER:      WormWars 7.21
  3.  *                            
  4.  * © Copyright 1993-2002 James R. Jacobs. Freely distributable.
  5.  */
  6.  
  7. #include <string.h>
  8. #include <math.h>
  9. #include <stdio.h>
  10. #include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE */
  11. #include <assert.h>
  12. #define ASSERT
  13.  
  14. #include "stdafx.h"
  15. #include "diff.h"
  16. #include "same.h"
  17.  
  18. #define OTTER_UP    0
  19. #define OTTER_DOWN  1
  20. #define OTTER_LEFT  2
  21. #define OTTER_RIGHT 3
  22.  
  23. #define ARROWX               (FIELDX + 1)
  24. #define BONUSSPEEDUP         8 // 8 times more common on bonus levels
  25. #define NOSE                 2 // if (NOSE > PROTECTORS) nose disabled
  26. #define WORMQUEUELIMIT      15
  27. #define DOGQUEUELIMIT      120
  28. #define TIMELIMIT          599
  29. #define SECONDSPERLEVEL    120 // assert (SECONDSPERLEVEL <= TIMELIMIT);
  30. #define WEIGHT               5
  31.  
  32. // dog dormancy
  33. #define DORMANT              0
  34. #define AWAKENING            1
  35. #define CHASING             10
  36.  
  37. // population limits
  38. #define CREATURES           50
  39. #define MAGNETS             20
  40. #define PROTECTORS           2 // <=4!
  41. #define OCTOPI              12 // this limit applies only to predefined octopi
  42.  
  43. #define FREQ_BIRD          140
  44. #define FREQ_CLOUD          55
  45. #define FREQ_CLOUDFIRE      30
  46. #define FREQ_DOG            55
  47. #define FREQ_DRIP           15
  48. #define FREQ_FISH          105
  49. #define FREQ_GIRAFFE        50
  50. #define FREQ_GOAT           35
  51. #define FREQ_GOATFIRE       10
  52. #define FREQ_GOATMOVE        5
  53. #define FREQ_LION           50
  54. #define FREQ_LIONTURN       20
  55. #define FREQ_OCTOPUS        95
  56. #define FREQ_OCTOPUSFIRE    40
  57. #define FREQ_OCTOPUSSPIN     3
  58. #define FREQ_ORB            35
  59. #define FREQ_PENGUIN        50
  60. #define FREQ_SLIME          80
  61. #define FREQ_SLIMEGROW      75
  62. #define FREQ_TELEPORT      210
  63. #define FREQ_TIMEBOMB      210
  64.  
  65. #define SPEED_BIRD          13
  66. #define SPEED_CLOUD          9
  67. #define SPEED_DOG            3
  68. #define SPEED_DRIP           4
  69. #define SPEED_FISH          12
  70. #define SPEED_FRAGMENT       3
  71. #define SPEED_GIRAFFE      255 // giraffe never needs to move
  72. #define SPEED_GOAT          16
  73. #define SPEED_LION           9
  74. #define SPEED_MAGNET         9
  75. #define SPEED_MISSILE        7
  76. #define SPEED_OCTOPUS       16
  77. #define SPEED_ORB            6
  78. #define SPEED_OTTER         19
  79. #define SPEED_PENGUIN       11
  80. #define SPEED_TIMEBOMB      60
  81. #define SPEED_WHIRLWIND      1
  82.  
  83. #define HARDNESS_BIRD       50
  84. #define HARDNESS_CLOUD      50
  85. #define HARDNESS_DOG        50
  86. #define HARDNESS_DRIP       50
  87. #define HARDNESS_FISH       50
  88. #define HARDNESS_FRAGMENT   50
  89. #define HARDNESS_GIRAFFE    50
  90. #define HARDNESS_GOAT       50
  91. #define HARDNESS_LION       60
  92. #define HARDNESS_MISSILE    50
  93. #define HARDNESS_OCTOPUS    50
  94. #define HARDNESS_OTTER      95
  95. #define HARDNESS_ORB        50
  96. #define HARDNESS_PENGUIN    10
  97. #define HARDNESS_TIMEBOMB   80
  98. #define HARDNESS_WHIRLWIND  90
  99.  
  100. #define DISTANCE_FAST        5
  101. #define DISTANCE_BIRD        3
  102. #define DISTANCE_GIRAFFE     5
  103. #define DISTANCE_NORMAL      4
  104. #define DISTANCE_NOSE        4
  105. #define DISTANCE_SLOW        3
  106. #define DISTANCE_VERYSLOW    2
  107.  
  108. #define POINTS_EMPTY         1
  109. #define POINTS_DYNAMITE      5
  110. #define POINTS_TURNSILVER    5
  111. #define POINTS_ENCLOSURE    10
  112. #define POINTS_SILVER       10
  113. #define POINTS_TURNGOLD     10
  114. #define POINTS_GOLD         20
  115. #define POINTS_LETTER      100
  116. #define POINTS_GRAVE       100
  117.  
  118. #define  ADD_BOMB      5 // in squares radius
  119. #define  ADD_CLOCK    10 // in seconds
  120. #define  ADD_CUTTER   10 // in VERYSLOWs
  121. #define  ADD_GLOW     30 // in VERYSLOWs
  122. #define  ADD_ICE      10 // in VERYSLOWs
  123. #define  ADD_ARMOUR   25 // in VERYSLOWs
  124. #define  ADD_TREASURE 10 // in seconds
  125. #define RAND_BOMB     25
  126. #define RAND_CLOCK    20
  127. #define RAND_CUTTER   20
  128. #define RAND_GLOW     50
  129. #define RAND_ICE       5
  130. #define RAND_ARMOUR   25
  131. #define RAND_TREASURE 10
  132.  
  133. MODULE  void changefield(void);
  134. MODULE  void death(void);
  135. MODULE  void fastloop(void);
  136. MODULE  void killall(void);
  137. MODULE  void magnetloop(void);
  138. MODULE  void newhiscores(void);
  139. MODULE  void slowloop(void);
  140. MODULE  void ReadGameports(void);
  141. MODULE  void endoflevel(void);
  142.  
  143. MODULE  void bangdynamite(SBYTE x, SBYTE y, SBYTE player);
  144. MODULE  void bombblast(SBYTE triggerer, SBYTE player, SBYTE centrex, SBYTE centrey);
  145. MODULE  void bothcol(SBYTE player, SBYTE x, SBYTE y);
  146. MODULE  void bounceoffcreature(UBYTE which, SBYTE x, SBYTE y);
  147. MODULE  void __inline change(SBYTE x, SBYTE y, UBYTE image);
  148. MODULE  void checkrectangle(SBYTE direction, SBYTE player, SBYTE horizontalsize, SBYTE verticalsize);
  149. MODULE  void cloudbullet(UBYTE which, SBYTE x, SBYTE y, SBYTE deltay);
  150. MODULE  void creatureloop(SBYTE which);
  151. MODULE  void dogqueue(SBYTE which, SBYTE deltax, SBYTE deltay);
  152. MODULE  void drawcause(SBYTE player, SBYTE state);
  153. MODULE  void newlevel(UBYTE player);
  154. MODULE  void orbsplit(SBYTE which);
  155. MODULE  void protcol(SBYTE player, SBYTE x, SBYTE y, SBYTE thisprot);
  156. MODULE  void putnumber(void);
  157. MODULE  void ramming(SBYTE player);
  158. MODULE  void reflect(UBYTE which);
  159. MODULE  void turnworm(SBYTE player, SBYTE deltax, SBYTE deltay);
  160. MODULE  void updatearrow(SBYTE arrowy);
  161. MODULE  void wormbullet(SBYTE player);
  162. MODULE  void wormloop(SBYTE player);
  163. MODULE  void wormcol(SBYTE player, SBYTE x, SBYTE y);
  164.  
  165. MODULE void wormworm(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2);
  166. MODULE void protworm(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2);
  167. MODULE void protprot(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2);
  168. MODULE void octopusfire(UBYTE which);
  169. MODULE void squareblast(SBYTE type, SBYTE player, UBYTE c, SBYTE x, SBYTE y, ABOOL cutter);
  170. MODULE void drawmissile(SBYTE x, SBYTE y, UBYTE which);
  171.  
  172. MODULE SWORD atleast(SWORD value, SWORD minimum);
  173. MODULE ABOOL blocked(UBYTE which, SBYTE deltax, SBYTE deltay);
  174. MODULE ABOOL bouncecreature(UBYTE which, SBYTE x, SBYTE y);
  175. MODULE SBYTE bsign(SBYTE value);
  176. MODULE ABOOL findempty(SBYTE* x, SBYTE* y, ABOOL mode);
  177. MODULE FLAG  getnumber(SBYTE player);
  178. MODULE SBYTE onlyworm(ABOOL alive);
  179. MODULE SBYTE slowdown(SBYTE speed, ABOOL brakes);
  180. MODULE SBYTE speedup(SBYTE speed, ABOOL brakes);
  181. MODULE UBYTE whichcreature(SBYTE x, SBYTE y, UBYTE species, UBYTE exception);
  182. MODULE SBYTE whichteleport(SBYTE x, SBYTE y);
  183. MODULE ULONG wormobject(UBYTE player, SBYTE x, SBYTE y);
  184.  
  185. MODULE void wormkillcreature(UBYTE player, UBYTE which);
  186. MODULE void createcreature(UBYTE species, UBYTE which, SBYTE x, SBYTE y, SBYTE deltax, SBYTE deltay, UBYTE player);
  187. MODULE ULONG arand(ULONG number);
  188. MODULE void protcreature(UBYTE player, UBYTE which);
  189. MODULE void wormcreature(UBYTE player, UBYTE which);
  190. MODULE void creaturecreature(UBYTE which1, UBYTE which2);
  191.  
  192. /* PRIVATE STRUCTURES -------------------------------------------------- */
  193.  
  194. struct
  195. {   SBYTE x, y, deltax, deltay;
  196.     ABOOL alive, moved, teleported, visible, reflected;
  197. } bullet[9];
  198. struct
  199. {   UWORD freq;
  200.     ULONG score;
  201. } object[LASTOBJECT + 1] =
  202. {   {1590,  60}, // AFFIXER
  203.     {  65,  20}, // AMMO
  204.     { 105,  20}, // ARMOUR
  205.     {  90,  50}, // BIAS
  206.     { 130,  30}, // BOMB
  207.     { 115,  10}, // BONUS
  208.     { 280,  10}, // BRAKES
  209.     { 890,  60}, // CLOCK
  210.     { 370,  50}, // CONVERTER
  211.     { 300,  80}, // CUTTER
  212.     { 255,  90}, // CYCLONE
  213.     { 315,  20}, // ENCLOSER
  214.     { 115,  30}, // GLOW
  215.     { 205,  50}, // GROWER
  216.     {1900,  90}, // HEALER
  217.     { 950,  60}, // ICE
  218.     { 140,  60}, // LIFE
  219.     { 165,  80}, // LIGHTNING
  220.     { 930,  80}, // MAGNET
  221.     { 210,  40}, // MISSILE
  222.     { 630,  50}, // MULTIPLIER
  223.     { 235,  30}, // POWER
  224.     { 465,  50}, // PROTECTOR
  225.     { 210,  40}, // PULSE
  226.     { 300,  50}, // PUSHER
  227.     { 400,  40}, // REMNANTS
  228.     { 500,  30}, // SIDESHOT
  229.     { 480,  40}, // SLAYER
  230.     { 975,  40}, // SLOWER
  231.     { 710,  70}, // SWITCHER
  232.     {1490, 120}, // TREASURE
  233.     {3885, 140}  // UMBRELLA
  234. };
  235.  
  236. /*  -200    common
  237.     220-400 uncommon
  238.     420-980 rare
  239.     1000+   very rare */
  240.  
  241. struct
  242. {   SBYTE x, y, deltax, deltay, relx, rely;
  243.     ABOOL alive, last, visible;
  244. } protector[4][PROTECTORS + 1];
  245. struct
  246. {   SBYTE deltax, deltay;
  247. } thewormqueue[4][WORMQUEUELIMIT + 1];
  248. struct
  249. {   SBYTE deltax, deltay;
  250. } thedogqueue[CREATURES + 1][DOGQUEUELIMIT + 1];
  251. struct
  252. {   ABOOL alive;
  253.     SBYTE x, y, player;
  254.     UBYTE object;
  255. } magnet[MAGNETS + 1];
  256.  
  257. AGLOBAL UBYTE missileframes[4][MISSILEFRAMES + 1] =
  258. { { FIRSTMISSILE,
  259.     FIRSTMISSILEFRAME,
  260.     FIRSTMISSILEFRAME + 1,
  261.     FIRSTMISSILEFRAME + 2,
  262.     FIRSTMISSILEFRAME + 3,
  263.     FIRSTMISSILEFRAME + 4
  264.   },
  265.   { FIRSTMISSILE + 1,
  266.     FIRSTMISSILEFRAME + 5,
  267.     FIRSTMISSILEFRAME + 6,
  268.     FIRSTMISSILEFRAME + 7,
  269.     FIRSTMISSILEFRAME + 8,
  270.     FIRSTMISSILEFRAME + 9
  271.   },
  272.   { FIRSTMISSILE + 2,
  273.     FIRSTMISSILEFRAME + 10,
  274.     FIRSTMISSILEFRAME + 11,
  275.     FIRSTMISSILEFRAME + 12,
  276.     FIRSTMISSILEFRAME + 13,
  277.     FIRSTMISSILEFRAME + 14,
  278.   },
  279.   { FIRSTMISSILE + 3,
  280.     FIRSTMISSILEFRAME + 15,
  281.     FIRSTMISSILEFRAME + 16,
  282.     FIRSTMISSILEFRAME + 17,
  283.     FIRSTMISSILEFRAME + 18,
  284.     FIRSTMISSILEFRAME + 19
  285. } };
  286.  
  287. UBYTE eachworm[4][2][9] =
  288. { { { GREENHEAD_NW,  GREENHEADUP,   GREENHEAD_NE,
  289.       GREENHEADLEFT, ANYTHING,      GREENHEADRIGHT,
  290.       GREENHEAD_SW,  GREENHEADDOWN, GREENHEAD_SE
  291.     },
  292.     { GREENGLOW_NW,  GREENGLOWUP,   GREENGLOW_NE,
  293.       GREENGLOWLEFT, ANYTHING,      GREENGLOWRIGHT,
  294.       GREENGLOW_SW,  GREENGLOWDOWN, GREENGLOW_SE
  295.   } },
  296.   { { REDHEAD_NW,    REDHEADUP,     REDHEAD_NE,
  297.       REDHEADLEFT,   ANYTHING,      REDHEADRIGHT,
  298.       REDHEAD_SW,    REDHEADDOWN,   REDHEAD_SE
  299.     },
  300.     { REDGLOW_NW,    REDGLOWUP,     REDGLOW_NE,
  301.       REDGLOWLEFT,   ANYTHING,      REDGLOWRIGHT,
  302.       REDGLOW_SW,    REDGLOWDOWN,   REDGLOW_SE
  303.   } },
  304.   { { BLUEHEAD_NW,   BLUEHEADUP,    BLUEHEAD_NE,
  305.       BLUEHEADLEFT,  ANYTHING,      BLUEHEADRIGHT,
  306.       BLUEHEAD_SW,   BLUEHEADDOWN,  BLUEHEAD_SE
  307.     },
  308.     { BLUEGLOW_NW,   BLUEGLOWUP,    BLUEGLOW_NE,
  309.       BLUEGLOWLEFT,  ANYTHING,      BLUEGLOWRIGHT,
  310.       BLUEGLOW_SW,   BLUEGLOWDOWN,  BLUEGLOW_SE
  311.   } },
  312.   { { YELLOWHEAD_NW, YELLOWHEADUP,  YELLOWHEAD_NE,
  313.       YELLOWHEADLEFT,ANYTHING,      YELLOWHEADRIGHT,
  314.       YELLOWHEAD_SW, YELLOWHEADDOWN,YELLOWHEAD_SE
  315.     },
  316.     { YELLOWGLOW_NW, YELLOWGLOWUP,  YELLOWGLOW_NE,
  317.       YELLOWGLOWLEFT,ANYTHING,      YELLOWGLOWRIGHT,
  318.       YELLOWGLOW_SW, YELLOWGLOWDOWN,YELLOWGLOW_SE
  319. } } };
  320.  
  321. UBYTE eachtail[4][2][9][9] = {
  322. { { { GN_SE_NW,      GN_SE_N,       GN_SE_NE, // going NW (delta -1, -1)
  323.       GN_SE_W,       WHATEVER,      GN_SE_E,  // (so starting from SE)
  324.       GN_SE_SW,      GN_SE_S,       GN_SE_NW
  325.     },
  326.     { GN_S_NW,       GN_S_N,        GN_S_NE,  // going N (delta 0, -1)
  327.       GN_S_W,        WHATEVER,      GN_S_E,   // (so starting from S)
  328.       GN_S_SW,       GN_S_N,        GN_S_SE
  329.     },
  330.     { GN_SW_NW,      GN_SW_N,       GN_SW_NE, // going NE (delta 0, 1)
  331.       GN_SW_W,       WHATEVER,      GN_SW_E,  // (so starting from SW)
  332.       GN_SW_NE,      GN_SW_S,       GN_SW_SE
  333.     },
  334.     { GN_E_NW,       GN_E_N,        GN_E_NE,  // going W (delta -1, 0)
  335.       GN_E_W,        WHATEVER,      GN_E_W,   // (so starting from E)
  336.       GN_E_SW,       GN_E_S,        GN_E_SE
  337.     },
  338.     { GN_SE_NW,      GN_S_N,        GN_SW_NE, // going nowhere (delta 0, 0)
  339.       GN_E_W,        WHATEVER,      GN_W_E,  
  340.       GN_NE_SW,      GN_N_S,        GN_NW_SE
  341.     },
  342.     { GN_W_NW,       GN_W_N,        GN_W_NE,  // going E (delta 1, 0)
  343.       GN_W_E,        WHATEVER,      GN_W_E,   // (so starting from W)
  344.       GN_W_SW,       GN_W_S,        GN_W_SE
  345.     },
  346.     { GN_NE_NW,      GN_NE_N,       GN_NE_NW, // going SW (delta -1, 1)
  347.       GN_NE_W,       WHATEVER,      GN_NE_E,  // (so starting from NE)
  348.       GN_NE_SW,      GN_NE_S,       GN_NE_SE
  349.     },
  350.     { GN_N_NW,       GN_N_S,        GN_N_NE,  // going S (delta 0, 1)
  351.       GN_N_W,        WHATEVER,      GN_N_E,   // (so starting from N)
  352.       GN_N_SW,       GN_N_S,        GN_N_SE
  353.     },
  354.     { GN_NW_SE,      GN_NW_N,       GN_NW_NE, // going SE (delta 1, 1)
  355.       GN_NW_W,       WHATEVER,      GN_NW_E,  // (so starting from NW)
  356.       GN_NW_SW,      GN_NW_S,       GN_NW_SE
  357.   } },
  358.   { { GG_SE_NW,      GG_SE_N,       GG_SE_NE, // going NW (delta -1, -1)
  359.       GG_SE_W,       WHATEVER,      GG_SE_E,  // (so starting from SE)
  360.       GG_SE_SW,      GG_SE_S,       GG_SE_NW
  361.     },
  362.     { GG_S_NW,       GG_S_N,        GG_S_NE,  // going N (delta 0, -1)
  363.       GG_S_W,        WHATEVER,      GG_S_E,   // (so starting from S)
  364.       GG_S_SW,       GG_S_N,        GG_S_SE
  365.     },
  366.     { GG_SW_NW,      GG_SW_N,       GG_SW_NE, // going NE (delta 0, 1)
  367.       GG_SW_W,       WHATEVER,      GG_SW_E,  // (so starting from SW)
  368.       GG_SW_NE,      GG_SW_S,       GG_SW_SE
  369.     },                
  370.     { GG_E_NW,       GG_E_N,        GG_E_NE,  // going W (delta -1, 0)
  371.       GG_E_W,        WHATEVER,      GG_E_W,   // (so starting from E)
  372.       GG_E_SW,       GG_E_S,        GG_E_SE
  373.     },
  374.     { GG_SE_NW,      GG_S_N,        GG_SW_NE, // going nowhere (delta 0, 0)
  375.       GG_E_W,        WHATEVER,      GG_W_E,  
  376.       GG_NE_SW,      GG_N_S,        GG_NW_SE
  377.     },
  378.     { GG_W_NW,       GG_W_N,        GG_W_NE,  // going E (delta 1, 0)
  379.       GG_W_E,        WHATEVER,      GG_W_E,   // (so starting from W)
  380.       GG_W_SW,       GG_W_S,        GG_W_SE
  381.     },
  382.     { GG_NE_NW,      GG_NE_N,       GG_NE_SW, // going SW (delta -1, 1)
  383.       GG_NE_W,       WHATEVER,      GG_NE_E,  // (so starting from NE)
  384.       GG_NE_SW,      GG_NE_S,       GG_NE_SE
  385.     },
  386.     { GG_N_NW,       GG_N_S,        GG_N_NE,  // going S (delta 0, 1)
  387.       GG_N_W,        WHATEVER,      GG_N_E,   // (so starting from N)
  388.       GG_N_SW,       GG_N_S,        GG_N_SE
  389.     },
  390.     { GG_NW_SE,      GG_NW_N,       GG_NW_NE, // going SE (delta 1, 1)
  391.       GG_NW_W,       WHATEVER,      GG_NW_E,  // (so starting from NW)
  392.       GG_NW_SW,      GG_NW_S,       GG_NW_SE
  393. } } },
  394. { { { RN_SE_NW,      RN_SE_N,       RN_SE_NE, // going NW (delta -1, -1)
  395.       RN_SE_W,       WHATEVER,      RN_SE_E,  // (so starting from SE)
  396.       RN_SE_SW,      RN_SE_S,       RN_SE_NW,
  397.     },                              
  398.     { RN_S_NW,       RN_S_N,        RN_S_NE,  // going N (delta 0, -1)
  399.       RN_S_W,        WHATEVER,      RN_S_E,   // (so starting from S)
  400.       RN_S_SW,       RN_S_N,        RN_S_SE
  401.     },
  402.     { RN_SW_NW,      RN_SW_N,       RN_SW_NE, // going NE (delta 0, 1)
  403.       RN_SW_W,       WHATEVER,      RN_SW_E,  // (so starting from SW)
  404.       RN_SW_NE,      RN_SW_S,       RN_SW_SE
  405.     },
  406.     { RN_E_NW,       RN_E_N,        RN_E_NE,  // going W (delta -1, 0)
  407.       RN_E_W,        WHATEVER,      RN_E_W,   // (so starting from E)
  408.       RN_E_SW,       RN_E_S,        RN_E_SE
  409.     },
  410.     { RN_SE_NW,      RN_S_N,        RN_SW_NE, // going nowhere (delta 0, 0)
  411.       RN_E_W,        WHATEVER,      RN_W_E,  
  412.       RN_NE_SW,      RN_N_S,        RN_NW_SE
  413.     },
  414.     { RN_W_NW,       RN_W_N,        RN_W_NE,  // going E (delta 1, 0)
  415.       RN_W_E,        WHATEVER,      RN_W_E,   // (so starting from W)
  416.       RN_W_SW,       RN_W_S,        RN_W_SE
  417.     },
  418.     { RN_NE_NW,      RN_NE_N,       RN_NE_SW, // going SW (delta -1, 1)
  419.       RN_NE_W,       WHATEVER,      RN_NE_E,  // (so starting from NE)
  420.       RN_NE_SW,      RN_NE_S,       RN_NE_SE
  421.     },
  422.     { RN_N_NW,       RN_N_S,        RN_N_NE,  // going S (delta 0, 1)
  423.       RN_N_W,        WHATEVER,      RN_N_E,   // (so starting from N)
  424.       RN_N_SW,       RN_N_S,        RN_N_SE
  425.     },
  426.     { RN_NW_SE,      RN_NW_N,       RN_NW_NE, // going SE (delta 1, 1)
  427.       RN_NW_W,       WHATEVER,      RN_NW_E,  // (so starting from NW)
  428.       RN_NW_SW,      RN_NW_S,       RN_NW_SE
  429.   } },
  430.   { { RG_SE_NW,      RG_SE_N,       RG_SE_NE, // going NW (delta -1, -1)
  431.       RG_SE_W,       WHATEVER,      RG_SE_E,  // (so starting from SE)
  432.       RG_SE_SW,      RG_SE_S,       RG_SE_NW
  433.     },
  434.     { RG_S_NW,       RG_S_N,        RG_S_NE,  // going N (delta 0, -1)
  435.       RG_S_W,        WHATEVER,      RG_S_E,   // (so starting from S)
  436.       RG_S_SW,       RG_S_N,        RG_S_SE
  437.     },
  438.     { RG_SW_NW,      RG_SW_N,       RG_SW_NE, // going NE (delta 0, 1)
  439.       RG_SW_W,       WHATEVER,      RG_SW_E,  // (so starting from SW)
  440.       RG_SW_NE,      RG_SW_S,       RG_SW_SE
  441.     },
  442.     { RG_E_NW,       RG_E_N,        RG_E_NE,  // going W (delta -1, 0)
  443.       RG_E_W,        WHATEVER,      RG_E_W,   // (so starting from E)
  444.       RG_E_SW,       RG_E_S,        RG_E_SE
  445.     },
  446.     { RG_SE_NW,      RG_S_N,        RG_SW_NE, // going nowhere (delta 0, 0)
  447.       RG_E_W,        WHATEVER,      RG_W_E,  
  448.       RG_NE_SW,      RG_N_S,        RG_NW_SE
  449.     },
  450.     { RG_W_NW,       RG_W_N,        RG_W_NE,  // going E (delta 1, 0)
  451.       RG_W_E,        WHATEVER,      RG_W_E,   // (so starting from W)
  452.       RG_W_SW,       RG_W_S,        RG_W_SE
  453.     },
  454.     { RG_NE_NW,      RG_NE_N,       RG_NE_SW, // going SW (delta -1, 1)
  455.       RG_NE_W,       WHATEVER,      RG_NE_E,  // (so starting from NE)
  456.       RG_NE_SW,      RG_NE_S,       RG_NE_SE
  457.     },
  458.     { RG_N_NW,       RG_N_S,        RG_N_NE,  // going S (delta 0, 1)
  459.       RG_N_W,        WHATEVER,      RG_N_E,   // (so starting from N)
  460.       RG_N_SW,       RG_N_S,        RG_N_SE
  461.     },
  462.     { RG_NW_SE,      RG_NW_N,       RG_NW_NE, // going SE (delta 1, 1)
  463.       RG_NW_W,       WHATEVER,      RG_NW_E,  // (so starting from NW)
  464.       RG_NW_SW,      RG_NW_S,       RG_NW_SE
  465. } } },
  466. { { { BN_NW_SE,      BN_N_SE,       BN_NE_SE, // going NW (delta -1, -1)
  467.       BN_W_SE,       WHATEVER,      BN_E_SE,  // (so starting from SE)
  468.       BN_SW_SE,      BN_S_SE,       BN_NW_SE
  469.     },                              
  470.     { BN_NW_S,       BN_N_S,        BN_NE_S,  // going N (delta 0, -1)
  471.       BN_W_S,        WHATEVER,      BN_E_S,   // (so starting from S)
  472.       BN_S_SW,       BN_N_S,        BN_S_SE
  473.     },
  474.     { BN_NW_SW,      BN_N_SW,       BN_NE_SW, // going NE (delta 0, 1)
  475.       BN_W_SW,       WHATEVER,      BN_SW_E,  // (so starting from SW)
  476.       BN_NE_SW,      BN_S_SW,       BN_SW_SE
  477.     },
  478.     { BN_NW_E,       BN_N_E,        BN_E_NE,  // going W (delta -1, 0)
  479.       BN_W_E,        WHATEVER,      BN_W_E,   // (so starting from E)
  480.       BN_SW_E,       BN_E_S,        BN_E_SE
  481.     },
  482.     { BN_NW_SE,      BN_N_S,        BN_NE_SW, // going nowhere (delta 0, 0)
  483.       BN_W_E,        WHATEVER,      BN_W_E,  
  484.       BN_NE_SW,      BN_N_S,        BN_NW_SE
  485.     },
  486.     { BN_W_NW,       BN_N_W,        BN_W_NE,  // going E (delta 1, 0)
  487.       BN_W_E,        WHATEVER,      BN_W_E,   // (so starting from W)
  488.       BN_W_SW,       BN_W_S,        BN_W_SE
  489.     },
  490.     { BN_NW_NE,      BN_N_NE,       BN_NE_SW, // going SW (delta -1, 1)
  491.       BN_W_NE,       WHATEVER,      BN_E_NE,  // (so starting from NE)
  492.       BN_NE_SW,      BN_NE_S,       BN_NE_SE
  493.     },
  494.     { BN_N_NW,       BN_N_S,        BN_N_NE,  // going S (delta 0, 1)
  495.       BN_N_W,        WHATEVER,      BN_N_E,   // (so starting from N)
  496.       BN_N_SW,       BN_N_S,        BN_N_SE
  497.     },
  498.     { BN_SW_SE,      BN_N_NW,       BN_NW_NE, // going SE (delta 1, 1)
  499.       BN_W_NW,       WHATEVER,      BN_NW_E,  // (so starting from NW)
  500.       BN_NW_SW,      BN_NW_S,       BN_NW_SE
  501.   } },
  502.   { { BG_NW_SE,      BG_N_SE,       BG_NE_SE, // going NW (delta -1, -1)
  503.       BG_W_SE,       WHATEVER,      BG_E_SE,  // (so starting from SE)
  504.       BG_SW_SE,      BG_S_SE,       BG_NW_SE
  505.     },
  506.     { BG_NW_S,       BG_N_S,        BG_NE_S,  // going N (delta 0, -1)
  507.       BG_W_S,        WHATEVER,      BG_E_S,   // (so starting from S)
  508.       BG_S_SW,       BG_N_S,        BG_S_SE
  509.     },
  510.     { BG_NW_SW,      BG_N_SW,       BG_NE_SW, // going NE (delta 0, 1)
  511.       BG_W_SW,       WHATEVER,      BG_SW_E,  // (so starting from SW)
  512.       BG_NE_SW,      BG_S_SW,       BG_SW_SE
  513.     },
  514.     { BG_NE_E,       BG_N_E,        BG_NE_E,  // going W (delta -1, 0)
  515.       BG_W_E,        WHATEVER,      BG_W_E,   // (so starting from E)
  516.       BG_SW_E,       BG_E_S,        BG_E_SE
  517.     },
  518.     { BG_NW_SE,      BG_N_S,        BG_NE_SW, // going nowhere (delta 0, 0)
  519.       BG_W_E,        WHATEVER,      BG_W_E,  
  520.       BG_NE_SW,      BG_N_S,        BG_NW_SE
  521.     },
  522.     { BG_NW_W,       BG_N_W,        BG_NE_W,  // going E (delta 1, 0)
  523.       BG_W_E,        WHATEVER,      BG_W_E,   // (so starting from W)
  524.       BG_W_SW,       BG_W_S,        BG_W_SE
  525.     },
  526.     { BG_NW_NE,      BG_N_NE,       BG_NE_SW, // going SW (delta -1, 1)
  527.       BG_NE_W,       WHATEVER,      BG_NE_E,  // (so starting from NE)
  528.       BG_NE_SW,      BG_NE_S,       BG_NE_SE
  529.     },
  530.     { BG_N_NW,       BG_N_S,        BG_N_NE,  // going S (delta 0, 1)
  531.       BG_N_W,        WHATEVER,      BG_N_E,   // (so starting from N)
  532.       BG_N_SW,       BG_N_S,        BG_N_SE
  533.     },
  534.     { BG_NW_SE,      BG_N_NW,       BG_NW_NE, // going SE (delta 1, 1)
  535.       BG_NW_W,       WHATEVER,      BG_NW_E,  // (so starting from NW)
  536.       BG_NW_SW,      BG_NW_S,       BG_NW_SE
  537. } } },
  538. { { { YN_NW_SE,      YN_N_SE,       YN_NE_SE, // going NW (delta -1, -1)
  539.       YN_W_SE,       WHATEVER,      YN_E_SE,  // (so starting from SE)
  540.       YN_SW_SE,      YN_S_SE,       YN_NW_SE
  541.     },                              
  542.     { YN_NW_S,       YN_N_S,        YN_NE_S,  // going N (delta 0, -1)
  543.       YN_W_S,        WHATEVER,      YN_S_E,   // (so starting from S)
  544.       YN_S_SW,       YN_N_S,        YN_S_SE
  545.     },
  546.     { YN_NW_SW,      YN_N_SW,       YN_NE_SW, // going NE (delta 0, 1)
  547.       YN_W_SW,       WHATEVER,      YN_E_SW,  // (so starting from SW)
  548.       YN_NE_SW,      YN_S_SW,       YN_SW_SE
  549.     },
  550.     { YN_NW_E,       YN_N_E,        YN_NE_E,  // going W (delta -1, 0)
  551.       YN_W_E,        WHATEVER,      YN_W_E,   // (so starting from E)
  552.       YN_E_SW,       YN_S_E,        YN_E_SE
  553.     },
  554.     { YN_NW_SE,      YN_N_S,        YN_NE_SW, // going nowhere (delta 0, 0)
  555.       YN_W_E,        WHATEVER,      YN_W_E,  
  556.       YN_NE_SW,      YN_N_S,        YN_NW_SE
  557.     },
  558.     { YN_NW_W,       YN_N_W,        YN_W_NE,  // going E (delta 1, 0)
  559.       YN_W_E,        WHATEVER,      YN_W_E,   // (so starting from W)
  560.       YN_W_SW,       YN_W_S,        YN_W_SE
  561.     },
  562.     { YN_NW_NE,      YN_N_NE,       YN_NE_SW, // going SW (delta -1, 1)
  563.       YN_W_NE,       WHATEVER,      YN_NE_E,  // (so starting from NE)
  564.       YN_NE_SW,      YN_NE_S,       YN_NE_SE
  565.     },
  566.     { YN_N_NW,       YN_N_S,        YN_N_NE,  // going S (delta 0, 1)
  567.       YN_N_W,        WHATEVER,      YN_N_E,   // (so starting from N)
  568.       YN_N_SW,       YN_N_S,        YN_N_SE
  569.     },
  570.     { YN_NW_SE,      YN_N_NW,       YN_NW_NE, // going SE (delta 1, 1)
  571.       YN_NW_W,       WHATEVER,      YN_NW_E,  // (so starting from NW)
  572.       YN_NW_SW,      YN_NW_S,       YN_NW_SE
  573.   } },
  574.   { { YG_NW_SE,      YG_N_SE,       YG_NE_SE, // going NW (delta -1, -1)
  575.       YG_W_SE,       WHATEVER,      YG_E_SE,  // (so starting from SE)
  576.       YG_SW_SE,      YG_S_SE,       YG_NW_SE
  577.     },                              
  578.     { YG_S_NW,       YG_N_S,        YG_S_NE,  // going N (delta 0, -1)
  579.       YG_W_S,        WHATEVER,      YG_E_S,   // (so starting from S)
  580.       YG_S_SW,       YG_N_S,        YG_S_SE
  581.     },
  582.     { YG_NW_SW,      YG_N_SW,       YG_NE_SW, // going NE (delta 0, 1)
  583.       YG_W_SW,       WHATEVER,      YG_E_SW,  // (so starting from SW)
  584.       YG_NE_SW,      YG_S_SW,       YG_SW_SE
  585.     },
  586.     { YG_E_NW,       YG_E_N,        YG_E_NE,  // going W (delta -1, 0)
  587.       YG_W_E,        WHATEVER,      YG_W_E,   // (so starting from E)
  588.       YG_E_SW,       YG_E_S,        YG_E_SE
  589.     },
  590.     { YG_NW_SE,      YG_N_S,        YG_NE_SW, // going nowhere (delta 0, 0)
  591.       YG_W_E,        WHATEVER,      YG_W_E,  
  592.       YG_NE_SW,      YG_N_S,        YG_NW_SE
  593.     },
  594.     { YG_W_NW,       YG_N_W,        YG_W_NE,  // going E (delta 1, 0)
  595.       YG_W_E,        WHATEVER,      YG_W_E,   // (so starting from W)
  596.       YG_W_SW,       YG_W_S,        YG_W_SE
  597.     },
  598.     { YG_NW_NE,      YG_N_NE,       YG_NE_SW, // going SW (delta -1, 1)
  599.       YG_W_NE,       WHATEVER,      YG_E_NE,  // (so starting from NE)
  600.       YG_NE_SW,      YG_S_NE,       YG_NE_SE
  601.     },
  602.     { YG_N_NW,       YG_N_S,        YG_N_NE,  // going S (delta 0, 1)
  603.       YG_N_W,        WHATEVER,      YG_E_N,   // (so starting from N)
  604.       YG_N_SW,       YG_N_S,        YG_N_SE
  605.     },
  606.     { YG_NW_SE,      YG_N_NW,       YG_NW_NE, // going SE (delta 1, 1)
  607.       YG_W_NW,       WHATEVER,      YG_E_NW,  // (so starting from NW)
  608.       YG_NW_SW,      YG_S_NW,       YG_NW_SE
  609. } } }
  610. };
  611.  
  612. /* Rules for variable types:
  613.  
  614. SBYTE is used for field coordinates and queue indexes
  615. UBYTE is used for field contents
  616. SWORD is used for frequencies
  617. ULONG is used for scores */
  618.  
  619. struct
  620. {   ABOOL alive, visible;
  621.     SBYTE x, y, deltax, deltay, pos, time, dir;
  622.     UBYTE dormant, multi, speed, last, oldlast, species, hardness, frame,
  623.           journey, going, then,
  624.           type; // type is worm 0-3 (for drips, missiles, dogs and birds)
  625.     SWORD freq;
  626.     ULONG score;
  627. } creature[CREATURES + 1];
  628.  
  629. // MODULE VARIABLES (used only within engine.c) ---------------------------
  630.  
  631. MODULE ABOOL banging  = FALSE,
  632.              first    = TRUE,
  633.              enclosed = FALSE,
  634.              trainer;
  635. MODULE UBYTE infector[FIELDX + 1][FIELDY + 1],
  636.              ice,
  637.              leveltype;
  638. MODULE SBYTE numberx,
  639.              numbery,
  640.              number,
  641.              treasurer;
  642.  
  643. // GLOBAL VARIABLES -------------------------------------------------------
  644.  
  645. ABOOL anims      = TRUE,
  646.       clearthem  = FALSE,
  647.       modified   = FALSE,
  648.       randomflag = FALSE,
  649.       randomarray[MAXLEVELS + 1],
  650.       thick      = FALSE,
  651.       turbo      = FALSE;
  652. UBYTE board[MAXLEVELS + 1][FIELDX + 1][FIELDY + 1],
  653.       field[FIELDX + 1][FIELDY + 1];
  654. SBYTE a = GAMEOVER,
  655.       players,
  656.       level = 1, levels, reallevel, sourcelevel,
  657.       startx[MAXLEVELS + 1], starty[MAXLEVELS + 1];
  658. SWORD secondsleft, secondsperlevel;
  659. TEXT  pathname[81],
  660.       date[DATELENGTH + 1],
  661.       times[TIMELENGTH + 1];
  662. ULONG delay, r;
  663.  
  664. AGLOBAL struct HiScoreStruct  hiscore[HISCORES + 1];
  665. AGLOBAL struct WormStruct     worm[4];
  666. AGLOBAL struct TeleportStruct teleport[MAXLEVELS + 1][4];
  667.  
  668. MODULE ABOOL blocked(UBYTE which, SBYTE deltax, SBYTE deltay)
  669. {   UBYTE c = field[xwrap(teleport[level][partner(which)].x + deltax)][ywrap(teleport[level][partner(which)].y + deltay)];
  670.     if (c == STONE || c == METAL || c == GOAT || c == OCTOPUS)
  671.         return TRUE;
  672.     else return FALSE;
  673. }
  674.  
  675. MODULE void bombblast(SBYTE triggerer, SBYTE player, SBYTE centrex, SBYTE centrey)
  676. {   SBYTE counter, downy, downymax, leftx, leftxmax, rightx, rightxmax, strength, uppy, uppymax, x, y;
  677.  
  678.     effect(FXUSE_BOMB);
  679.     strength = ADD_BOMB + arand(RAND_BOMB);
  680.  
  681.     leftxmax = centrex - strength;
  682.     if (leftxmax < 0)
  683.         leftxmax = 0;
  684.     rightxmax = centrex + strength;
  685.     if (rightxmax > FIELDX)
  686.         rightxmax = FIELDX;
  687.     uppymax = centrey - strength;
  688.     if (uppymax < 0)
  689.         uppymax = 0;
  690.     downymax = centrey + strength;
  691.     if (downymax > FIELDY)
  692.         downymax = FIELDY;
  693.  
  694.     leftx = centrex;
  695.     rightx = centrex;
  696.     uppy = centrey;
  697.     downy = centrey;
  698.     for (counter = 1; counter <= strength; counter++)
  699.     {   if (leftx > leftxmax)
  700.         {   leftx--;
  701.             for (y = uppy; y <= downy; y++)
  702.                 squareblast(triggerer, player, field[leftx][y], leftx, y, FALSE);
  703.         }
  704.         if (uppy > uppymax)
  705.         {   uppy--;
  706.             for (x = leftx; x <= rightx; x++)
  707.                 squareblast(triggerer, player, field[x][uppy], x, uppy, FALSE);
  708.         }
  709.         if (rightx < rightxmax)
  710.         {   rightx++;
  711.             for (y = downy; y >= uppy; y--)
  712.                 squareblast(triggerer, player, field[rightx][y], rightx, y, FALSE);
  713.         }
  714.         if (downy < downymax)
  715.         {   downy++;
  716.             for (x = rightx; x >= leftx; x--)
  717.                 squareblast(triggerer, player, field[x][downy], x, downy, FALSE);
  718. }   }   }
  719.  
  720. MODULE void bounceoffcreature(UBYTE which, SBYTE x, SBYTE y)
  721. {   UBYTE killed;
  722.  
  723.     if (field[x][y] == GOAT || field[x][y] == OCTOPUS || field[x][y] == FISH)
  724.     {   killed = whichcreature(x, y, field[x][y], which);
  725.         creature[killed].alive = FALSE;
  726.         change(x, y, BONUS);
  727. }   }
  728.  
  729. MODULE ABOOL bouncecreature(UBYTE which, SBYTE x, SBYTE y)
  730. {   if
  731.     (    field[x][y] == METAL
  732.      ||  field[x][y] == STONE
  733.      ||  field[x][y] == WOOD
  734.      ||  field[x][y] == GOAT
  735.      ||  field[x][y] == OCTOPUS
  736.      ||  field[x][y] == FISH
  737.      || (field[x][y] >= FIRSTTAIL && field[x][y] <= LASTTAIL)
  738.     )
  739.     {   return TRUE;
  740.     } else
  741.     {   return FALSE;
  742. }   }
  743.  
  744. MODULE SBYTE bsign(SBYTE value)
  745. {   if (value < 0)
  746.         return (-1);
  747.     elif (value > 0)
  748.         return (1);
  749.     else return (0);
  750. }
  751.  
  752. MODULE void changefield(void)
  753. {   SBYTE x, y;
  754.  
  755.     if (randomflag && a == PLAYGAME && level)
  756.     {   do
  757.         {    sourcelevel = arand(levels - 1) + 1;
  758.         } while (randomarray[level]);
  759.         randomarray[level] = TRUE;
  760.     } else sourcelevel = level;
  761.  
  762.     for (x = 0; x <= FIELDX; x++)
  763.         for (y = 0; y <= FIELDY; y++)
  764.             field[x][y] = board[sourcelevel][x][y];
  765. }
  766.  
  767. void clearhiscores(void)
  768. {   SBYTE i;
  769.     
  770.     clearthem = FALSE;
  771.     for (i = 0; i <= HISCORES; i++)
  772.     {   hiscore[i].player = -1;
  773.         hiscore[i].level = 0;
  774.         hiscore[i].score = 0;
  775.         hiscore[i].fresh = FALSE;
  776.         hiscore[i].name[0] = 0;
  777.         hiscore[i].time[0] = 0;
  778.         hiscore[i].date[0] = 0;
  779. }   }
  780.  
  781. MODULE void death(void)
  782. {   SBYTE pain, player;
  783.     UBYTE which;
  784.     ABOOL slow;
  785.  
  786.     for (player = 0; player <= 3; player++)
  787.     {   if (worm[player].lives)
  788.         {   if (!worm[player].alive)
  789.             {   slow = FALSE;
  790.                 pain = 0;
  791.                 if (worm[player].cause >= FIRSTTAIL && worm[player].cause <= LASTTAIL)
  792.                 {   if (player == worm[player].cause - FIRSTTAIL)
  793.                         pain = PAIN_FRIENDLYTAIL;
  794.                     else pain = PAIN_ENEMYTAIL;
  795.                     slow = TRUE;
  796.                 } elif (worm[player].cause >= FIRSTGLOW && worm[player].cause <= LASTGLOW)
  797.                 {   pain = PAIN_GLOW;
  798.                     slow = TRUE;
  799.                 } elif (worm[player].cause >= FIRSTFIRE && worm[player].cause <= LASTFIRE)
  800.                     pain = PAIN_WORMFIRE;
  801.                 elif (worm[player].cause >= FIRSTHEAD && worm[player].cause <= LASTHEAD)
  802.                     pain = PAIN_HEAD;
  803.                 elif (worm[player].cause >= FIRSTPROTECTOR && worm[player].cause <= LASTPROTECTOR)
  804.                     pain = PAIN_PROTECTOR;
  805.                 elif (worm[player].cause >= FIRSTMISSILE && worm[player].cause <= LASTMISSILE)
  806.                     pain = PAIN_MISSILE;
  807.                 elif (worm[player].cause >= FIRSTDRIP && worm[player].cause <= LASTDRIP)
  808.                     pain = PAIN_DRIP;
  809.                 else switch (worm[player].cause)
  810.                 {
  811.                 case GOAT:
  812.                     pain = PAIN_GOAT;
  813.                     slow = TRUE;
  814.                 break;
  815.                 case OCTOPUS:
  816.                     pain = PAIN_OCTOPUS;
  817.                     slow = TRUE;
  818.                 break;
  819.                 case METAL:
  820.                     pain = PAIN_METAL;
  821.                     slow = TRUE;
  822.                 break;
  823.                 case SLIME:
  824.                     pain = PAIN_SLIME;
  825.                     slow = TRUE;
  826.                 break;
  827.                 case STONE:
  828.                     pain = PAIN_STONE;
  829.                     slow = TRUE;
  830.                 break;
  831.                 case TELEPORT:
  832.                     pain = PAIN_TELEPORT;
  833.                     slow = TRUE;
  834.                 break;
  835.                 case WOOD:
  836.                     pain = PAIN_WOOD;
  837.                     slow = TRUE;
  838.                 break;
  839.                 case BIRD:
  840.                     pain = PAIN_BIRD;
  841.                 break;
  842.                 case BOMB:
  843.                     pain = PAIN_BOMB;
  844.                 break;
  845.                 case CLOUD:
  846.                     pain = PAIN_CLOUD;
  847.                 break;
  848.                 case DOG:
  849.                     pain = PAIN_DOG;
  850.                 break;
  851.                 case FRAGMENT:
  852.                     pain = PAIN_FRAGMENT;
  853.                 break;
  854.                 case LIGHTNING:
  855.                     pain = PAIN_LIGHTNING;
  856.                 break;
  857.                 case ORB:
  858.                     pain = PAIN_ORB;
  859.                 break;
  860.                 case OTTER:
  861.                     pain = PAIN_OTTER;
  862.                 break;
  863.                 case PENGUIN:
  864.                     pain = PAIN_PENGUIN;
  865.                 break;
  866.                 case SLAYER:
  867.                     pain = PAIN_SLAYER;
  868.                 break;
  869.                 case WHIRLWIND:
  870.                     pain = PAIN_WHIRLWIND;
  871.                 break;
  872.                 default:
  873.                     // assert(0);
  874.                 break;
  875.                 }
  876.                 if (worm[player].victor >= 0 && worm[player].victor != player)
  877.                 {   if (worm[worm[player].victor].bias)
  878.                     {   worm[worm[player].victor].lives += pain;
  879.                         stat(worm[player].victor, LIFE);
  880.                 }   }
  881.                 if (slow)
  882.                 {   worm[player].speed = slowdown(worm[player].speed, worm[player].brakes);
  883.                     stat(player, BRAKES); 
  884.                 }
  885.                 if (pain > worm[player].lives)
  886.                     worm[player].lives = 0;
  887.                 else worm[player].lives -= pain;
  888.  
  889.                 draw(worm[player].x, worm[player].y, FIRSTPAIN + player);
  890.                 drawcause(player, NORMAL);
  891.                 stat(player, LIFE);
  892.                 if (level)
  893.                     worm[player].levelreached = level;
  894.                 else worm[player].levelreached = reallevel;
  895.                 if (worm[player].lives)
  896.                 {   effect(FXPAIN + player);
  897.                     worm[player].alive = TRUE;
  898.                     worm[player].causewait = r + CAUSEWAIT;
  899.                 } else
  900.                 {   /* kill worm */
  901.                     effect(FXDEATH_WORM);
  902.                     change(worm[player].x, worm[player].y, FIRSTGRAVE + player);
  903.                     updatearrow(worm[player].y);
  904.                     for (which = 0; which <= PROTECTORS; which++)
  905.                         if (protector[player][which].alive && protector[player][which].visible)
  906.                             change(protector[player][which].x, protector[player][which].y, EMPTY);
  907.                     for (which = 0; which <= MAGNETS; which++)
  908.                         if (magnet[which].player == player)
  909.                             magnet[which].alive = FALSE;
  910.                     if (worm[player].score >= worm[player].hiscore)
  911.                         worm[player].hiscore = worm[player].score;
  912.     }   }   }   }
  913.  
  914.     if (!worm[0].lives && !worm[1].lives && !worm[2].lives && !worm[3].lives)
  915.     {   /* End of game */
  916.         for (player = 0; player <= 3; player++)
  917.             if (worm[player].control != NONE && worm[player].score >= worm[player].hiscore)
  918.                 worm[player].hiscore = worm[player].score;
  919.         newhiscores();
  920.         effect(FXGAMEOVER);
  921.         a = GAMEOVER;
  922.         if (players == 1)
  923.             say((STRPTR) "Game over!", worm[onlyworm(FALSE)].colour);
  924.         elif (worm[0].control && ((!worm[1].control) || worm[1].score < worm[0].score) && ((!worm[2].control) || worm[2].score < worm[0].score) && ((!worm[3].control) || worm[3].score < worm[0].score))
  925.             say((STRPTR) "Green wins!", GREEN);
  926.         elif (worm[1].control && ((!worm[0].control) || worm[0].score < worm[1].score) && ((!worm[2].control) || worm[2].score < worm[1].score) && ((!worm[3].control) || worm[3].score < worm[1].score))
  927.             say((STRPTR) "Red wins!", RED);
  928.         elif (worm[2].control && ((!worm[0].control) || worm[0].score < worm[2].score) && ((!worm[1].control) || worm[1].score < worm[2].score) && ((!worm[3].control) || worm[3].score < worm[2].score))
  929.             say((STRPTR) "Blue wins!", BLUE);
  930.         elif (worm[3].control && ((!worm[0].control) || worm[0].score < worm[3].score) && ((!worm[1].control) || worm[1].score < worm[3].score) && ((!worm[2].control) || worm[2].score < worm[3].score))
  931.             say((STRPTR) "Yellow wins!", YELLOW);
  932.         else say((STRPTR) "A draw!", WHITE);
  933.         waitasec();
  934.         anykey(FALSE);
  935. }   }
  936.  
  937. MODULE void drawcause(SBYTE player, SBYTE state)
  938. {   if (state == BLACK)
  939.     {   draw
  940.         (   -6,
  941.             (player * 10) + 8,
  942.             BLACKENED
  943.         );
  944.     } else
  945.     {   draw
  946.         (   -6,
  947.             (player * 10) + 8,
  948.             worm[player].cause
  949.         );
  950. }   }
  951.  
  952. /* NAME    enginesetup -- once-only initialization of engine variables
  953. SYNOPSIS   enginesetup(void);
  954. FUNCTION   Sets up the unchanging worm variables.
  955. MODULE     engine.c */
  956.  
  957. void enginesetup(void)
  958. {   worm[0].statx = worm[0].staty = worm[1].staty = worm[2].statx = 0;
  959.     worm[1].statx = worm[2].staty = worm[3].statx = worm[3].staty = 1;
  960.     worm[0].colour = GREEN;
  961.     worm[1].colour = RED;
  962.     worm[2].colour = BLUE;
  963.     worm[3].colour = YELLOW;
  964.     worm[0].dimcolour = DARKGREEN;
  965.     worm[1].dimcolour = DARKRED;
  966.     worm[2].dimcolour = DARKBLUE;
  967.     worm[3].dimcolour = DARKYELLOW;
  968.     worm[0].port = 2;
  969.     worm[1].port = 3;
  970.     worm[2].port = 1;
  971.     worm[3].port = 0;
  972.     worm[0].name[0] = worm[1].name[0] = worm[2].name[0] = worm[3].name[0] = 0;
  973.     worm[0].dynamitescore =
  974.     worm[1].dynamitescore =
  975.     worm[2].dynamitescore =
  976.     worm[3].dynamitescore = 0;
  977.  
  978.     strcpy(pathname, DEFAULTSET);
  979.  
  980.     systemsetup();
  981. }
  982.  
  983. /* NAME    fastloop -- things done often
  984. SYNOPSIS   fastloop(void);
  985. FUNCTION   Checks for and handles level completion.
  986. MODULE     engine.c */
  987.  
  988. MODULE void fastloop(void)
  989. {   SBYTE i, player, x, y;
  990.  
  991.     // all octopi spin together, but some may not be spinning, each may
  992.     // be in a different part of its spin.
  993.     if (!arand(FREQ_OCTOPUSSPIN))
  994.     {   for (i = 0; i <= CREATURES; i++)
  995.         {   if (creature[i].alive && creature[i].species == OCTOPUS && creature[i].dir >= 0)
  996.             {   octopusfire(i);
  997.     }   }   }
  998.  
  999.     // animate
  1000.     if (anims)
  1001.     {   for (i = 0; i <= CREATURES; i++)
  1002.         {   if (creature[i].alive && creature[i].visible)
  1003.             {   if (creature[i].species == BIRD)
  1004.                 {   if (!(r % 3))
  1005.                     {   creature[i].frame += creature[i].dir;
  1006.                         draw(creature[i].x, creature[i].y, BIRD + creature[i].frame);
  1007.                         if (creature[i].frame == 0)
  1008.                         {   creature[i].dir = 1;
  1009.                         } elif (creature[i].frame == 4)
  1010.                         {   creature[i].dir = -1;
  1011.                 }   }   }
  1012.                 elif (creature[i].species == MISSILE)
  1013.                 {   if (!(r % 3))
  1014.                     {   drawmissile(creature[i].x, creature[i].y, i);
  1015.                         if (++creature[i].frame > MISSILEFRAMES)
  1016.                         {   creature[i].frame = 0;
  1017.     }   }   }   }   }   }
  1018.  
  1019.     if (banging)
  1020.     {   banging = FALSE;
  1021.         for (x = 0; x <= FIELDX; x++)
  1022.             for (y = 0; y <= FIELDY; y++)
  1023.                 if (field[x][y] == BANGDYNAMITE)
  1024.                 {   change(x, y, SILVER);
  1025.                     bangdynamite(x, y, infector[x][y]);
  1026.                 }
  1027.         for (i = 0; i <= 3; i++)
  1028.             if (worm[i].dynamitescore)
  1029.             {   wormscore(i, worm[i].dynamitescore);
  1030.                 worm[i].dynamitescore = 0;
  1031.             }
  1032.         for (x = 0; x <= FIELDX; x++)
  1033.             for (y = 0; y <= FIELDY; y++)
  1034.                 if (field[x][y] == TEMPBANGDYNAMITE)
  1035.                 {   banging = TRUE;
  1036.                     field[x][y] = BANGDYNAMITE;
  1037.     }           }
  1038.  
  1039.     /* DYNAMITE PHILOSOPHY:
  1040.  
  1041.     Worm gets dynamite. Instantly the dynamite infects the surrounding
  1042.     dynamite into bang-dynamite.
  1043.         Each fastloop, you scan the field for bang-dynamite. For each
  1044.     piece you find, it turns to silver and infects any surrounding dynamite.
  1045.  
  1046.     flash letter */
  1047.  
  1048.     if (level)
  1049.     {   if (r % 8 == 1)
  1050.         {   draw(numberx, numbery, WHITENED);
  1051.         } elif (r % 8 == 2)
  1052.         {   draw(numberx, numbery, FIRSTLETTER + number - 1);
  1053.     }   }
  1054.  
  1055.     // flash icons
  1056.     for (player = 0; player <= 3; player++)
  1057.     {   icon(player, GLOW);
  1058.         icon(player, CUTTER);
  1059. }   }
  1060.  
  1061. MODULE ABOOL findempty(SBYTE* x, SBYTE* y, ABOOL mode)
  1062. {   SBYTE count = 0, xx, yy;
  1063.     UBYTE c;
  1064.  
  1065.     if (mode)
  1066.     {   do
  1067.         {   xx = arand(FIELDX);
  1068.             yy = arand(FIELDY);
  1069.             c  = field[xx][yy];
  1070.         } while ((c != SLIME && c != WOOD && c != STONE && c != METAL && (c < FIRSTTAIL || c > LASTTAIL)) && ++count < PATIENCE);
  1071.     } else
  1072.     {   do
  1073.         {   xx = arand(FIELDX);
  1074.             yy = arand(FIELDY);
  1075.             c  = field[xx][yy];
  1076.         } while ((c < FIRSTEMPTY || c > LASTEMPTY) && ++count < PATIENCE);
  1077.     }
  1078.  
  1079.     if (count < PATIENCE)
  1080.     {   *x = xx;
  1081.         *y = yy;
  1082.         return(TRUE);
  1083.     } else
  1084.     {   return(FALSE);
  1085. }   }
  1086.  
  1087. void gameloop(void)
  1088. {   SBYTE i, player;
  1089.  
  1090.     if (a == PLAYGAME)
  1091.     {   ReadGameports();
  1092.         fastloop();
  1093.         gameinput();
  1094.     }
  1095.     if (a == PLAYGAME)
  1096.     {   ReadGameports();
  1097.         for (player = 0; player <= 3; player++)
  1098.             if (worm[player].lives && !(r % worm[player].speed))
  1099.                 wormloop(player);
  1100.     }
  1101.     if (a == PLAYGAME)
  1102.     {   ReadGameports();
  1103.         for (i = 0; i <= CREATURES; i++)
  1104.         {   if (creature[i].alive && !(r % creature[i].speed) && (!ice || creature[i].species == MISSILE || creature[i].species == FRAGMENT))
  1105.             {   creatureloop(i);
  1106.     }   }   }
  1107.     if (a == PLAYGAME)
  1108.     {   ReadGameports();
  1109.         if (!(r % SPEED_MAGNET))
  1110.         {   magnetloop();
  1111.         }
  1112.         death();
  1113.     }
  1114.     if (a == PLAYGAME)
  1115.     {   ReadGameports();
  1116.         if (!(r % VERYSLOW))
  1117.         {   slowloop();
  1118.     }   }
  1119.     timing();
  1120. }
  1121.  
  1122. MODULE void killall(void)
  1123. {   UBYTE i;
  1124.  
  1125.     for (i = 0; i <= CREATURES; i++)
  1126.         creature[i].alive = FALSE;
  1127.     for (i = 0; i <= MAGNETS; i++)
  1128.         magnet[i].alive = FALSE;
  1129.     teleport[level][2].alive = FALSE;
  1130.     teleport[level][3].alive = FALSE;
  1131. }
  1132.  
  1133. SBYTE loadfields(STRPTR fieldname)
  1134. {   SBYTE i, j, x, y;
  1135.     TEXT  IOBuffer[NAMELENGTH + 1];
  1136.     UBYTE ver;
  1137.  
  1138. #ifdef PLATFORM_IBM
  1139.     UBYTE amigaboard[AMIGAFIELDX + 1][FIELDY + 1];
  1140. #endif
  1141.  
  1142.     /* This routine is not entirely robust, especially regarding
  1143.     failures part way through reading. It is very trusting of its data;
  1144.     ie. it doesn't do any sanity checking.
  1145.  
  1146.     Provided that the fieldset was created with Worm Wars's built-in field
  1147.     editor, and the file is not corrupt, these failures should never
  1148.     happen anyway.
  1149.  
  1150.     open file */
  1151.  
  1152.     // say("Opening...", WHITE);
  1153.  
  1154.     if (!ZOpen(fieldname, FALSE))
  1155.         return 1; /* no harm done */
  1156.  
  1157.     /* read header
  1158.  
  1159.     say("Reading header...", WHITE);
  1160.  
  1161.     FSET 7.0#!
  1162.     0123456789
  1163.  
  1164.     # is the NULL terminator
  1165.     ! is levels */
  1166.  
  1167.     if (!ZRead(IOBuffer, 10))
  1168.     {    ZClose();
  1169.         return 2; /* no harm done */
  1170.     }
  1171.     if (!strcmp(IOBuffer, "FSET 7.0"))
  1172.     {   ver = 70;
  1173.     } elif (!strcmp(IOBuffer, "FSET 7.2"))
  1174.     {   ver = 72;
  1175.     } else
  1176.     {   ZClose();
  1177.         return 3; /* no harm done */
  1178.     }
  1179.     levels = IOBuffer[9];
  1180.  
  1181.     /* read high score table */
  1182.  
  1183.     // say("Reading high score table...", WHITE);
  1184.  
  1185.     for (i = 0; i <= HISCORES; i++)
  1186.     {   if (!ZRead(IOBuffer, 6))
  1187.         {    ZClose();
  1188.              return 4; /* incorrect levels */
  1189.         }
  1190.         hiscore[i].fresh                        =  FALSE;
  1191.         hiscore[i].player                       =  IOBuffer[0];
  1192.         hiscore[i].level                        =  IOBuffer[1];
  1193.         hiscore[i].score                        = (IOBuffer[2] * 16777216)
  1194.                                                 + (IOBuffer[3] * 65536)
  1195.                                                 + (IOBuffer[4] * 256)
  1196.                                                 +  IOBuffer[5];
  1197.  
  1198.         if (!ZRead(IOBuffer, NAMELENGTH + 1))
  1199.         {   ZClose();
  1200.             return 5; /* incorrect levels, corrupted high scores */
  1201.         }
  1202.         for (j = 0; j <= NAMELENGTH; j++)
  1203.         {   hiscore[i].name[j]              = IOBuffer[j];
  1204.         }
  1205.         if (!ZRead(IOBuffer, TIMELENGTH + 1))
  1206.         {   ZClose();
  1207.             return 6; /* incorrect levels, corrupted high scores */
  1208.         }
  1209.         for (j = 0; j <= TIMELENGTH; j++)
  1210.         {   hiscore[i].time[j]      = IOBuffer[j];
  1211.         }
  1212.         if (!ZRead(IOBuffer, DATELENGTH + 1))
  1213.         {   ZClose();
  1214.             return 7; /* incorrect levels, corrupted high scores */
  1215.         }
  1216.         for (j = 0; j <= DATELENGTH; j++)
  1217.         {   hiscore[i].date[j]      = IOBuffer[j];
  1218.     }   }
  1219.  
  1220.     // say("Reading level data...", WHITE);
  1221.  
  1222.     /* read level data */
  1223.  
  1224.     for (i = 0; i <= levels; i++)
  1225.     {   if (!ZRead(IOBuffer, 8))
  1226.         {   ZClose();
  1227.             return 9;
  1228.             /* incorrect levels, corrupted high scores,
  1229.             incorrect startx, teleports, field data */
  1230.         }
  1231.         startx[i]            =  IOBuffer[0];
  1232.         starty[i]            =  IOBuffer[1];
  1233.         teleport[i][0].alive =  IOBuffer[2];
  1234.         teleport[i][0].x     =  IOBuffer[3];
  1235.         teleport[i][0].y     =  IOBuffer[4];
  1236.         teleport[i][1].alive =  IOBuffer[5];
  1237.         teleport[i][1].x     =  IOBuffer[6];
  1238.         teleport[i][1].y     =  IOBuffer[7];
  1239.  
  1240. #ifdef PLATFORM_AMIGA
  1241.         if (!ZRead((char *) &board[i][0][0], LEVELSIZE))
  1242.         {   ZClose();
  1243.             return 10;
  1244.             /* incorrect levels, corrupted high scores,
  1245.             incorrect startx, teleports, field data */
  1246.         }
  1247. #endif
  1248. #ifdef PLATFORM_IBM
  1249.         startx[i]        += 6;
  1250.         teleport[i][0].x += 6;
  1251.         teleport[i][0].y += 6;
  1252.         if (!ZRead((char *) &amigaboard[0][0], LEVELSIZE))
  1253.         {   ZClose();
  1254.             return 10;
  1255.             /* incorrect levels, corrupted high scores,
  1256.             incorrect startx, teleports, field data */
  1257.         }
  1258.  
  1259.         // skip 6
  1260.         for (x = 0; x <= 5; x++)
  1261.         {   {   for (y = 0; y <= FIELDY; y++)
  1262.                 {   board[i][x][y] = EMPTY;
  1263.         }   }   }
  1264.         for (x = 0; x <= AMIGAFIELDX; x++)
  1265.         {   for (y = 0; y <= FIELDY; y++)
  1266.             {   board[i][x + 6][y] = amigaboard[x][y];
  1267.         }   }
  1268.         // skip 7
  1269.         for (x = AMIGAFIELDX + 6 + 1; x <= FIELDX; x++)
  1270.         {   for (y = 0; y <= FIELDY; y++)
  1271.             {   board[i][x][y] = EMPTY;
  1272.         }   }
  1273. #endif
  1274.         if (ver == 70)
  1275.         {   for (x = 0; x <= FIELDX; x++)
  1276.             {   for (y = 0; y <= FIELDY; y++)
  1277.                 {   if (board[i][x][y] >= 6 && board[i][x][y] <= 19) // CLOCK thru MULTIPLIER
  1278.                     {   board[i][x][y]++;
  1279.                     } elif (board[i][x][y] == 20) // NITRO (BRAKES)
  1280.                     {   board[i][x][y] = 6;
  1281.     }   }   }   }   }
  1282.  
  1283.     // say("Open done.", WHITE);
  1284.  
  1285.     // no need to read version string
  1286.     ZClose();
  1287.     modified = FALSE;
  1288.     return 0;
  1289. }
  1290.  
  1291. MODULE void magnetloop(void)
  1292. {   SBYTE i;
  1293.     UBYTE c;
  1294.  
  1295.     for (i = 0; i <= MAGNETS; i++)
  1296.     {   if (magnet[i].alive)
  1297.         {   // defensive programming to ensure magnet is still valid
  1298.             if (field[magnet[i].x][magnet[i].y] != magnet[i].object)
  1299.             {   magnet[i].alive = FALSE;
  1300.             } else
  1301.             {   change(magnet[i].x, magnet[i].y, EMPTY);
  1302.                 magnet[i].x += bsign(worm[magnet[i].player].x - magnet[i].x);
  1303.                 magnet[i].y += bsign(worm[magnet[i].player].y - magnet[i].y);
  1304.                 c = field[magnet[i].x][magnet[i].y];
  1305.            
  1306.                 if
  1307.                 (   (c >= FIRSTEMPTY && c <= LASTEMPTY)
  1308.                  || (c >= FIRSTTAIL  && c <= LASTTAIL)
  1309.                  || (c >= FIRSTGLOW  && c <= LASTGLOW)
  1310.                 )
  1311.                 {   change(magnet[i].x, magnet[i].y, magnet[i].object);
  1312.                 } elif (c >= FIRSTHEAD && c <= LASTHEAD)
  1313.                 {   change(magnet[i].x, magnet[i].y, magnet[i].object);
  1314.                     wormscore(c - FIRSTHEAD, wormobject(c - FIRSTHEAD, magnet[i].x, magnet[i].y));
  1315.                     change(magnet[i].x, magnet[i].y, FIRSTHEAD + magnet[i].player); // not entirely the right head image
  1316.                 } else magnet[i].alive = FALSE;
  1317. }   }   }   }
  1318.  
  1319. AGLOBAL void matchteleports(void)
  1320. {   AUTO UWORD teleports, octopi;
  1321.     AUTO SBYTE x, y, i;
  1322.  
  1323.     say("Checking fieldset...", WHITE);
  1324.     for (i = 0; i <= levels; i++)
  1325.     {   teleports = octopi = 0;
  1326.         teleport[level][0].alive = teleport[level][1].alive = FALSE;
  1327.  
  1328.         for (y = 0; y <= FIELDY; y++)
  1329.         {   for (x = 0; x <= FIELDX; x++)
  1330.             {   if (board[level][x][y] == TELEPORT)
  1331.                 {   teleports++;
  1332.                     if (teleports <= 2)
  1333.                     {   teleport[level][teleports - 1].x = x;
  1334.                         teleport[level][teleports - 1].y = y;
  1335.                     } else
  1336.                     {   board[level][x][y] = EMPTY;
  1337.                 }   }
  1338.                 elif (board[level][x][y] == OCTOPUS)
  1339.                 {   octopi++;
  1340.                     if (octopi > OCTOPI)
  1341.                     {   board[level][x][y] = EMPTY;
  1342.         }   }   }   }
  1343.  
  1344.         if (teleports == 1)
  1345.         {   board[level][teleport[level][0].x][teleport[level][0].y] = EMPTY;
  1346.         } elif (teleports >= 2)
  1347.         {   teleport[level][0].alive = teleport[level][1].alive = TRUE;
  1348. }   }   }
  1349.  
  1350. AGLOBAL void newfield(void)
  1351. {   SBYTE x, y;
  1352.  
  1353.     teleport[level][0].alive = FALSE;
  1354.     teleport[level][1].alive = FALSE;
  1355.     startx[level] = CENTREX;
  1356.     starty[level] = CENTREY;
  1357.  
  1358.     if (level)
  1359.     {   for (x = 0; x <= FIELDX; x++)
  1360.         {   for (y = 0; y <= FIELDY; y++)
  1361.             {   board[level][x][y] = EMPTY;
  1362.     }   }   }
  1363.     else
  1364.     {   for (x = 0; x <= FIELDX; x++)
  1365.         {   for (y = 0; y <= FIELDY; y++)
  1366.             {   board[0][x][y] = SILVER;
  1367. }   }   }   }
  1368.  
  1369. void newfields(void)
  1370. {   if (verify())
  1371.     {   strcpy(pathname, DEFAULTSET);
  1372.         levels = DEFAULTLEVELS;
  1373.         modified = FALSE;
  1374.         for (level = 0; level <= levels; level++)
  1375.             newfield();
  1376.         clearhiscores();
  1377.         level = 1;
  1378.         if (a == FIELDEDIT)
  1379.         {   turborender();
  1380.             saylevel(WHITE);
  1381.         } else hiscores();
  1382. }   }
  1383.  
  1384. void newgame(void)
  1385. {   SBYTE i, player;
  1386.  
  1387.     players = 0;
  1388.     for (player = 0; player <= 3; player++)
  1389.     {   if (worm[player].control != NONE)
  1390.             players++;
  1391.         worm[player].lives = 0;
  1392.         worm[player].speed = NORMAL;
  1393.         worm[player].hiscore = 0;
  1394.     }
  1395.     for (i = 1; i <= MAXLEVELS; i++)
  1396.        randomarray[i] = FALSE;
  1397.  
  1398.     r         = -1;
  1399.     trainer   = FALSE;
  1400.     ice       = 0;
  1401.     reallevel = 0;
  1402.     level     = 1;
  1403.     a         = PLAYGAME;
  1404.     clearscreen();
  1405.     newlevel(arand(3));
  1406.     timing();
  1407. }
  1408.  
  1409. MODULE void newhiscores(void)
  1410. {   PERSIST TEXT  amiganame[4][NAMELENGTH + 1] = {"Jay Miner", "Carl Sassenrath", "R. J. Mical", "Dave Morse"};
  1411.     AUTO    SBYTE i, j, player;
  1412.  
  1413.     datestamp();
  1414.     for (player = 0; player <= 3; player++)
  1415.         for (i = 0; i <= HISCORES; i++)
  1416.             if (worm[player].control != NONE && worm[player].score >= hiscore[i].score)
  1417.             {   /* push all worse hiscores down */
  1418.  
  1419.                 if (i < HISCORES)
  1420.                     for (j = HISCORES; j >= i + 1; j--)
  1421.                     {   hiscore[j].player     = hiscore[j - 1].player;
  1422.                         hiscore[j].level      = hiscore[j - 1].level;
  1423.                         hiscore[j].score      = hiscore[j - 1].score;
  1424.                         hiscore[j].fresh      = hiscore[j - 1].fresh;
  1425.                         strcpy(hiscore[j].name, hiscore[j - 1].name);
  1426.                         strcpy(hiscore[j].date, hiscore[j - 1].date);
  1427.                         strcpy(hiscore[j].time, hiscore[j - 1].time);
  1428.                     }
  1429.                 modified = TRUE;
  1430.                 hiscore[i].player = player;
  1431.                 hiscore[i].level  = worm[player].levelreached;
  1432.                 hiscore[i].score  = worm[player].hiscore;
  1433.                 if (worm[player].control == AMIGA)
  1434.                 {   strcpy(hiscore[i].name, amiganame[player]);
  1435.                     hiscore[i].fresh = FALSE;
  1436.                 } else
  1437.                 {   strcpy(hiscore[i].name, "(New)");
  1438.                     hiscore[i].fresh = TRUE;
  1439.                 }
  1440.                 strcpy(hiscore[i].time, times);
  1441.                 strcpy(hiscore[i].date, date);
  1442.                 break; /* vital */
  1443. }           }
  1444.  
  1445. MODULE void newlevel(UBYTE player)
  1446. {   SBYTE i, j;
  1447.     UWORD octopi = 0;
  1448.     UBYTE x, y;
  1449.  
  1450.     if (level >= 2)
  1451.         rundown(player);
  1452.     if (a == PLAYGAME)
  1453.     {   if (level > levels)
  1454.         {   for (i = 0; i <= 3; i++)
  1455.             {   if (worm[i].lives)
  1456.                     worm[i].levelreached = -1;
  1457.                 if (worm[player].control != NONE && worm[player].score >= worm[player].hiscore)
  1458.                     worm[player].hiscore = worm[player].score;
  1459.             }
  1460.             celebrate();
  1461.             newhiscores();
  1462.             titlescreen();
  1463.         } else
  1464.         {   saylevel(WHITE);
  1465.  
  1466.             for (i = 0; i <= 3; i++)
  1467.             {   if (worm[i].multi > 1)
  1468.                 {   worm[i].multi   /= 2;
  1469.                 }
  1470.                 worm[i].remnants =
  1471.                 worm[i].encloser =
  1472.                 worm[i].pusher   = FALSE;
  1473.             }
  1474.             killall();
  1475.             changefield();
  1476.             for (x = 0; x <= FIELDX; x++)
  1477.             {   for (y = 0; y <= FIELDY; y++)
  1478.                 {   if (board[level][x][y] == OCTOPUS)
  1479.                     {   octopi++;
  1480.                         if (octopi <= OCTOPI)
  1481.                         {   for (i = 0; i <= CREATURES; i++)
  1482.                             {   if (!creature[i].alive)
  1483.                                 {   createcreature(OCTOPUS, i, x, y, 0, 0, 255);
  1484.                                     break;
  1485.             }   }   }   }   }   }
  1486.  
  1487.             for (i = 0; i <= 3; i++)
  1488.             {   worm[i].speed = NORMAL;
  1489.                 if (worm[i].lives)
  1490.                     stat(i, BRAKES);
  1491.                 worm[i].moved = FALSE;
  1492.                 worm[i].numbers = 0;
  1493.                 worm[i].x = startx[sourcelevel];
  1494.                 worm[i].y = starty[sourcelevel];
  1495.                 worm[i].arrowy = worm[i].y;
  1496.         switch(i)
  1497.         {
  1498.         case 0:
  1499.             worm[0].deltax = -1;
  1500.             worm[0].deltay = 0;
  1501.         break;
  1502.         case 1:
  1503.             worm[1].deltax = 1;
  1504.             worm[1].deltay = 0;
  1505.         break;
  1506.         case 2:
  1507.             worm[2].deltax = 0;
  1508.             worm[2].deltay = -1;
  1509.         break;
  1510.         case 3:
  1511.             worm[3].deltax = 0;
  1512.             worm[3].deltay = 1;
  1513.         break;
  1514.         default:
  1515.         break;
  1516.             }   }
  1517.             turborender();
  1518.             delay = DELAY;
  1519.             if (level > 5)
  1520.             {   delay = delay / 4 * 3;
  1521.             }
  1522.             if (level > 10)
  1523.             {   delay = delay / 4 * 3;
  1524.             }
  1525.             if (level > 20)
  1526.             {   delay = delay / 4 * 3;
  1527.             }
  1528.  
  1529.             if (level)
  1530.             {   secondsperlevel = SECONDSPERLEVEL;
  1531.  
  1532.                 number = 1;
  1533.                 putnumber();
  1534.  
  1535.                 for (i = 0; i <= 3; i++)
  1536.                 {   if (!worm[i].lives && worm[i].control != NONE)
  1537.                     {   /* create (or resurrect) a worm */
  1538.  
  1539.                         worm[i].lives      = STARTLIVES;
  1540.                         worm[i].score      = 0;
  1541.                         worm[i].oldscore   = 0;
  1542.                         worm[i].armour     = 0;
  1543.                         worm[i].alive      = TRUE;
  1544.                         worm[i].power      = 0;
  1545.                         worm[i].bias       = 0;
  1546.                         worm[i].multi      = 1;
  1547.                         worm[i].victor     = -1;
  1548.                         worm[i].ammo       = 0;
  1549.                         worm[i].glow       = 0;
  1550.                         worm[i].remnants   =
  1551.                         worm[i].affixer    =
  1552.                         worm[i].sideshot   =
  1553.                         worm[i].pusher     =
  1554.                         worm[i].flashed    =
  1555.                         worm[i].encloser   =
  1556.                         worm[i].rammed     =
  1557.                         worm[i].frosted    =
  1558.                         worm[i].brakes      = FALSE;
  1559.                         worm[i].causewait  = (ULONG) -1;
  1560.                         worm[i].last       = FIRSTTAIL + i;
  1561.                         worm[i].pos        = -1;
  1562.                         worm[i].cutter     = 0;
  1563.                         worm[i].olddeltax  =
  1564.                         worm[i].olddeltay  = 0;
  1565.                         for (j = 0; j <= PROTECTORS; j++)
  1566.                         {   protector[i][j].alive = FALSE;
  1567.                         } for (j = 0; j <= LASTOBJECT; j++)
  1568.                         {   stat(i, j);
  1569.                             turbo = FALSE;
  1570.             }   }   }   }
  1571.             for (i = 0; i <= 3; i++)
  1572.             {   icon(i, REMNANTS);
  1573.                 icon(i, AFFIXER);
  1574.                 icon(i, SIDESHOT);
  1575.                 icon(i, PUSHER);
  1576.                 icon(i, GLOW);
  1577.                 icon(i, CUTTER);
  1578.                 icon(i, ENCLOSER);
  1579.     }   }   }
  1580.     clearkybd();
  1581.     resettime();
  1582. }
  1583.  
  1584. /* Many creatures take advantage of shared characteristics.
  1585. 11 creature types (orbs, goats, drips, fragments, missiles, penguins,
  1586. cyclones, dogs, clouds, timebombs, octopus) use the creature structure.
  1587. Independent of it are worms, protectors, worm bullets and teleports. */
  1588.  
  1589. MODULE void creatureloop(SBYTE which)
  1590. {   ABOOL happy = FALSE;
  1591.     UBYTE bestdistance, distance, player, c, i;
  1592.     SBYTE x, y, xx, yy, xxx, yyy, frontx, fronty, rearx, reary,
  1593.           deltax, deltay;
  1594.  
  1595.     x = creature[which].x;
  1596.     y = creature[which].y;
  1597.  
  1598.     if (!valid(x, y)) // defensive programming
  1599.     {   creature[which].alive = FALSE;
  1600.         return;
  1601.  
  1602.         /* TEXT temp1[SAYLIMIT + 1], temp2[8];
  1603.  
  1604.         strcpy(temp1, "BAD CREATURE AT x: ");
  1605.         stci_d(temp2, x);
  1606.         strcat(temp1, temp2);
  1607.         strcat(temp1, ", y: ");
  1608.         stci_d(temp2, y);
  1609.         strcat(temp1, temp2);
  1610.         strcat(temp1, "!");
  1611.         say(temp1, PURPLE);
  1612.         draw(FIELDX + 1, 0, creature[which].species); // indicates which creature
  1613.         Delay(250);
  1614.         clearkybd();
  1615.         anykey(FALSE); */
  1616.     }
  1617.  
  1618.     /* decide whether and where to move */
  1619.  
  1620.     switch(creature[which].species)
  1621.     {
  1622.     case BIRD:
  1623.         if (creature[which].type == 255)
  1624.         {   bestdistance = 255;
  1625.             for (player = 0; player <= 3; player++)
  1626.             {   if (worm[player].lives && !worm[player].bias)
  1627.                 {   xx = abs(worm[player].x - x);
  1628.                     yy = abs(worm[player].y - y);
  1629.                     if (xx > yy)
  1630.                         distance = xx;
  1631.                     else distance = yy;
  1632.                     if (distance <= DISTANCE_BIRD && distance < bestdistance)
  1633.                     {   effect(FXBORN_BIRD);
  1634.                         bestdistance = distance;
  1635.                         creature[which].type = player;
  1636.         }   }   }   }
  1637.         if (creature[which].type != 255) // if swooping
  1638.         {   if (worm[creature[which].type].lives && !worm[creature[which].type].bias)
  1639.             {   creature[which].deltax = bsign(worm[creature[which].type].x - x);
  1640.                 creature[which].deltay = bsign(worm[creature[which].type].y - y);
  1641.             } else
  1642.             {   creature[which].type = 255; // return to dormancy
  1643.                 creature[which].deltax = creature[which].deltay = 0;
  1644.         }   }
  1645.     break;
  1646.     case CLOUD:
  1647.         if (creature[which].x == 0 || creature[which].x == FIELDX)
  1648.             creature[which].deltax = -creature[which].deltax;
  1649.     break;
  1650.     case LION:
  1651.         if
  1652.         (   (creature[which].deltax == 0 && creature[which].deltay == 0)
  1653.         )
  1654.         {   if (arand(1) == 0)
  1655.             {   if (arand(1) == 0)
  1656.                 {   creature[which].deltax = -1;
  1657.                 } else
  1658.                 {   creature[which].deltax =  1;
  1659.                 }
  1660.                 creature[which].deltay = 0;
  1661.             } else
  1662.             {   if (arand(1) == 0)
  1663.                 {   creature[which].deltay = -1;
  1664.                 } else
  1665.                 {   creature[which].deltay =  1;
  1666.                 }
  1667.                 creature[which].deltax = 0;
  1668.         }   }
  1669.         elif (arand(FREQ_LIONTURN) == 0)
  1670.         {   if (creature[which].deltax)
  1671.             {   assert(creature[which].deltay == 0);
  1672.                 creature[which].deltax = 0;
  1673.                 if (arand(1) == 0)
  1674.                 {   creature[which].deltay = -1;
  1675.                 } else
  1676.                 {   creature[which].deltay = 1;
  1677.                 }
  1678.             } else
  1679.             {   assert(creature[which].deltay != 0);
  1680.                 creature[which].deltay = 0;
  1681.                 if (arand(1) == 0)
  1682.                 {   creature[which].deltax = -1;
  1683.                 } else
  1684.                 {   creature[which].deltax = 1;
  1685.         }   }   }
  1686.  
  1687.         if (!valid(x + creature[which].deltax, y + creature[which].deltay))
  1688.         {   creature[which].deltax = -creature[which].deltax;
  1689.             creature[which].deltay = -creature[which].deltay;
  1690.         } else
  1691.         {   frontx = xwrap(x + creature[which].deltax);  /* look in front */
  1692.             fronty = ywrap(y + creature[which].deltay);
  1693.             if (bouncecreature(which, frontx, fronty))
  1694.             {   bounceoffcreature(which, frontx, fronty);
  1695.                 creature[which].deltax = -creature[which].deltax;
  1696.                 creature[which].deltay = -creature[which].deltay;
  1697.         }   }
  1698.     break;
  1699.     case OTTER:
  1700.         if (secondsleft)
  1701.         {   return;
  1702.         }
  1703.         if (creature[which].journey == OTTER_RIGHT)
  1704.         {   switch(creature[which].going)
  1705.             {
  1706.             case OTTER_DOWN:
  1707.                 if (creature[which].y == FIELDY)
  1708.                 {   if (creature[which].x == FIELDX)
  1709.                     {   creature[which].journey = OTTER_LEFT;
  1710.                         creature[which].going = OTTER_UP;
  1711.                     } else
  1712.                     {   creature[which].going = OTTER_RIGHT;
  1713.                         creature[which].then  = OTTER_UP;
  1714.                 }   }
  1715.             break;
  1716.             case OTTER_RIGHT:
  1717.                 creature[which].going = creature[which].then;
  1718.             break;
  1719.             case OTTER_UP:             
  1720.                 if (creature[which].y == 0)
  1721.                 {   if (creature[which].x == FIELDX)
  1722.                     {   creature[which].journey = OTTER_LEFT;
  1723.                         creature[which].going = OTTER_DOWN;
  1724.                     } else
  1725.                     {   creature[which].going = OTTER_RIGHT;
  1726.                         creature[which].then  = OTTER_DOWN;
  1727.                 }   }
  1728.             break;
  1729.             default:
  1730.             break;
  1731.         }   }
  1732.         else
  1733.         {   // assert(creature[which].journey == OTTER_LEFT);
  1734.             switch(creature[which].going)
  1735.             {
  1736.             case OTTER_DOWN:
  1737.                 if (creature[which].y == FIELDY)
  1738.                 {   if (creature[which].x == 0)
  1739.                     {   creature[which].journey = OTTER_RIGHT;
  1740.                         creature[which].going = OTTER_UP;
  1741.                     } else
  1742.                     {   creature[which].going = OTTER_LEFT;
  1743.                         creature[which].then  = OTTER_UP;
  1744.                 }   }
  1745.             break;
  1746.             case OTTER_LEFT:
  1747.                 creature[which].going = creature[which].then;
  1748.             break;
  1749.             case OTTER_UP:             
  1750.                 if (creature[which].y == 0)
  1751.                 {   if (creature[which].x == 0)
  1752.                     {   creature[which].journey = OTTER_RIGHT;
  1753.                         creature[which].going = OTTER_DOWN;
  1754.                     } else
  1755.                     {   creature[which].going = OTTER_LEFT;
  1756.                         creature[which].then  = OTTER_DOWN;
  1757.                 }   }
  1758.             break;
  1759.             default:
  1760.                 // assert(0);
  1761.             break;
  1762.         }   }
  1763.  
  1764.         if (creature[which].going == OTTER_RIGHT)
  1765.         {   creature[which].deltax = 1;
  1766.             creature[which].deltay = 0;
  1767.         } elif (creature[which].going == OTTER_LEFT)
  1768.         {   creature[which].deltax = -1;
  1769.             creature[which].deltay = 0;
  1770.         } elif (creature[which].going == OTTER_UP)
  1771.         {   creature[which].deltax = 0;
  1772.             creature[which].deltay = -1;
  1773.         } elif (creature[which].going == OTTER_DOWN)
  1774.         {   creature[which].deltax = 0;
  1775.             creature[which].deltay = 1;
  1776.         }
  1777.     break;
  1778.     case TIMEBOMB:
  1779.     /* decrement and explode timebombs */
  1780.         if (field[x][y] != TIMEBOMB)
  1781.             creature[which].alive = FALSE;
  1782.         else
  1783.         {   effect(FXDO_BOMB);
  1784.             creature[which].time--;
  1785.             if (creature[which].time < 0)
  1786.             {   creature[which].alive = FALSE;
  1787.                 bombblast(BOMB, 0, x, y);
  1788.                 change(x, y, EMPTY);
  1789.             } else draw(x, y, ZERO + creature[which].time);
  1790.         }
  1791.         return; // not a bug
  1792.     break;
  1793.     case DOG:
  1794.         /* remove a movement from the dog queue */
  1795.  
  1796.         if (creature[which].dormant == CHASING)
  1797.         {   if (creature[which].pos != -1)
  1798.             {   creature[which].deltax = thedogqueue[which][0].deltax;
  1799.                 creature[which].deltay = thedogqueue[which][0].deltay;
  1800.                 if (--creature[which].pos != -1)
  1801.                 {   for (i = 0; i <= creature[which].pos; i++)
  1802.                     {   thedogqueue[which][i].deltax = thedogqueue[which][i + 1].deltax;
  1803.                         thedogqueue[which][i].deltay = thedogqueue[which][i + 1].deltay;
  1804.             }   }   }
  1805.             else creature[which].alive = FALSE;
  1806.         }
  1807.     break;
  1808.     case PENGUIN:
  1809.     do
  1810.         {   xx = arand(2) - 1;
  1811.             yy = arand(2) - 1;
  1812.     } while (!valid(x + xx, y + yy));
  1813.         c = field[x + xx][y + yy];
  1814.         if (c >= FIRSTEMPTY && c <= LASTEMPTY)
  1815.         {   creature[which].deltax = xx;
  1816.             creature[which].deltay = yy;
  1817.     } else
  1818.         {   creature[which].deltax = 0;
  1819.             creature[which].deltay = 0;
  1820.     }
  1821.     break;
  1822.     case WHIRLWIND:
  1823.         /* Whirlwinds have a slight upwards drift.
  1824.         Higher values of WEIGHT make it less buoyant. */
  1825.  
  1826.         creature[which].deltax = arand(2) - 1;
  1827.         if (!arand(WEIGHT))
  1828.             creature[which].deltay = arand(1) - 1;
  1829.         else creature[which].deltay = arand(2) - 1;
  1830.     break;
  1831.     case MISSILE:
  1832.         bestdistance = 255;
  1833.         for (player = 0; player <= 3; player++)
  1834.         {   if (creature[which].type != player && worm[player].lives)
  1835.             {   xx = abs(worm[player].x - x);
  1836.                 yy = abs(worm[player].y - y);
  1837.                 if (xx < yy)
  1838.                     distance = xx;
  1839.                 else distance = yy;
  1840.                 if (distance < bestdistance)
  1841.                 {   bestdistance = distance;
  1842.                     creature[which].deltax = bsign(worm[player].x - x);
  1843.                     creature[which].deltay = bsign(worm[player].y - y);
  1844.             }   }
  1845.             for (i = 0; i <= CREATURES; i++)
  1846.             {   if (creature[i].alive && which != i)
  1847.                 {   if
  1848.                     (   (   creature[i].species != DRIP
  1849.                          && creature[i].species != MISSILE
  1850.                         )
  1851.                          || creature[i].type != creature[which].type
  1852.                     )
  1853.                     {   xx = abs(creature[i].x - x);
  1854.                         yy = abs(creature[i].y - y);
  1855.                         if (xx < yy)
  1856.                             distance = xx;
  1857.                         else distance = yy;
  1858.                         if (distance < bestdistance)
  1859.                         {   bestdistance = distance;
  1860.                             creature[which].deltax = bsign(creature[i].x - x);
  1861.                             creature[which].deltay = bsign(creature[i].y - y);
  1862.         }   }   }   }   }
  1863.         if (bestdistance == 255)
  1864.         {   creature[which].alive = FALSE;
  1865.             change(x, y, EMPTY);
  1866.         }
  1867.     break;
  1868.     case ORB:
  1869.         frontx  = xwrap(x + creature[which].deltax);  /* look in front */
  1870.         fronty  = ywrap(y + creature[which].deltay);
  1871.         rearx   = xwrap(x - creature[which].deltax);  /* look behind */
  1872.         reary   = ywrap(y - creature[which].deltay);
  1873.         if (bouncecreature(which, frontx, fronty))
  1874.         {   bounceoffcreature(which, frontx, fronty);
  1875.             xx = -creature[which].deltax; /* default bounce angle is 180° */
  1876.             yy = -creature[which].deltay;
  1877.             if (!bouncecreature(which, frontx, reary))
  1878.             {   if (bouncecreature(which, rearx, fronty))
  1879.                 {   bounceoffcreature(which, rearx, fronty);
  1880.                     xx = creature[which].deltax;
  1881.             }   }
  1882.             elif (!bouncecreature(which, rearx, fronty))
  1883.             {   bounceoffcreature(which, rearx, fronty);
  1884.                 yy = creature[which].deltay;
  1885.             }
  1886.             creature[which].deltax = xx;
  1887.             creature[which].deltay = yy;
  1888.         }
  1889.     break;
  1890.     case FISH:
  1891.     do
  1892.         {   xx = arand(2) - 1;
  1893.             yy = arand(2) - 1;
  1894.     } while (!valid(x + xx, y + yy));
  1895.         c = field[x + xx][y + yy];
  1896.         if (c == SLIME || c == WOOD || c == STONE || c == METAL || (c >= FIRSTTAIL && c <= LASTTAIL))
  1897.         {   creature[which].deltax = xx;
  1898.             creature[which].deltay = yy;
  1899.             creature[which].last = creature[which].oldlast;
  1900.             if (c >= FIRSTTAIL && c <= LASTTAIL)
  1901.             {   creature[which].oldlast = c - FIRSTTAIL + FIRSTGLOW;
  1902.             } else creature[which].oldlast = c;    
  1903.         } else
  1904.         {   creature[which].deltax =
  1905.             creature[which].deltay = 0;
  1906.         }
  1907.     break;
  1908.     case GOAT:
  1909.         /* decide whether to move */
  1910.         if (!arand(FREQ_GOATMOVE))
  1911.         {   for (xx = x - 1; xx <= x + 1; xx++)
  1912.             {   for (yy = y - 1; yy <= y + 1; yy++)
  1913.                 {   if (valid(xx, yy) && field[xx][yy] >= FIRSTEMPTY && field[xx][yy] <= LASTEMPTY)
  1914.                     {   happy = TRUE;
  1915.                         break;
  1916.         }   }   }   }
  1917.         creature[which].deltax =
  1918.         creature[which].deltay = 0;
  1919.         if (!happy)
  1920.         {   xx = arand(2) - 1;
  1921.             yy = arand(2) - 1;
  1922.             if (valid(x + xx, y + yy) && (xx || yy))
  1923.             {   c = field[x + xx][y + yy];
  1924.                 if (c == SLIME || c == WOOD || c == STONE || c == METAL || (c >= FIRSTTAIL && c <= LASTTAIL))
  1925.                 {   creature[which].last = creature[which].oldlast;
  1926.                     creature[which].oldlast = c;
  1927.                     creature[which].deltax = xx;
  1928.                     creature[which].deltay = yy;
  1929.         }   }   }
  1930.     break;
  1931.     default: // octopus, giraffe
  1932.     break;
  1933.     }
  1934.  
  1935.     /* now move */
  1936.  
  1937.     if (creature[which].deltax || creature[which].deltay)
  1938.     {   if (creature[which].visible)
  1939.     {   /* erase previous image */
  1940.             change(x, y, creature[which].last);
  1941.             if (creature[which].species == OTTER)
  1942.             {   if ((worm[0].lives && worm[0].bias)
  1943.                  || (worm[1].lives && worm[1].bias)
  1944.                  || (worm[2].lives && worm[2].bias)
  1945.                  || (worm[3].lives && worm[3].bias))
  1946.                  {   creature[which].last = DYNAMITE;
  1947.                  } else creature[which].last = STONE;
  1948.             } else
  1949.             {   creature[which].last = EMPTY;
  1950.         }   }
  1951.     if (creature[which].alive)
  1952.     {   creature[which].x += creature[which].deltax;
  1953.         creature[which].y += creature[which].deltay;
  1954.         if (creature[which].species == ORB)
  1955.         {   creature[which].x = xwrap(creature[which].x);
  1956.             creature[which].y = ywrap(creature[which].y);
  1957.             } elif
  1958.             (   creature[which].species == DOG
  1959.              || creature[which].species == DRIP
  1960.              || creature[which].species == FRAGMENT
  1961.              || creature[which].species == WHIRLWIND
  1962.             )
  1963.         {    if (!valid(creature[which].x, creature[which].y))
  1964.                 {   creature[which].alive = FALSE;
  1965.     }   }   }   }
  1966.  
  1967.     creature[which].visible = TRUE;
  1968.     x = creature[which].x;
  1969.     y = creature[which].y;
  1970.  
  1971.     /* Collision detection. */
  1972.  
  1973.     if
  1974.     (    creature[which].alive
  1975.      &&  creature[which].species != FISH
  1976.      &&  creature[which].species != GIRAFFE
  1977.      &&  creature[which].species != GOAT
  1978.      &&  creature[which].species != PENGUIN
  1979.      &&  creature[which].species != OCTOPUS
  1980.      &&  creature[which].species != TIMEBOMB
  1981.      && (creature[which].deltax || creature[which].deltay)
  1982.     )
  1983.     {   c = field[x][y];
  1984.  
  1985.         if (c >= FIRSTHEAD && c <= LASTHEAD)
  1986.         {   wormcreature(c - FIRSTHEAD, which);
  1987.         } elif (c >= FIRSTPROTECTOR && c <= LASTPROTECTOR)
  1988.         {   protcreature(c - FIRSTPROTECTOR, which);
  1989.         } elif (c >= FIRSTTAIL && c <= LASTTAIL)
  1990.         {   ;
  1991.         } elif (c >= FIRSTLETTER && c <= LASTLETTER)
  1992.         {   creature[which].alive = FALSE;
  1993.         } elif (c == TIMEBOMB)
  1994.         {   if (creature[which].species != OTTER)
  1995.             {   creature[whichcreature(x, y, TIMEBOMB, which)].alive = FALSE;
  1996.             }
  1997.             bombblast(BOMB, 0, x, y);
  1998.             change(x, y, EMPTY);
  1999.         } elif (c >= FIRSTDRIP && c <= LASTDRIP)
  2000.         {   i = whichcreature(x, y, DRIP, which);
  2001.             creaturecreature(i, which);
  2002.         } elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
  2003.         {   i = whichcreature(x, y, MISSILE, which);
  2004.             creaturecreature(which, i);
  2005.         } elif
  2006.         (   c == BIRD
  2007.          || c == DOG
  2008.          || c == CLOUD
  2009.          || c == FISH
  2010.          || c == FRAGMENT
  2011.          || c == GIRAFFE
  2012.          || c == GOAT
  2013.          || c == LION
  2014.          || c == OCTOPUS
  2015.          || c == ORB
  2016.          || c == OTTER
  2017.          || c == PENGUIN
  2018.          || c == WHIRLWIND
  2019.         )
  2020.         {   i = whichcreature(x, y, c, which);
  2021.             creaturecreature(which, i);
  2022.         } elif (c == METAL)
  2023.         {   if (creature[which].species == DRIP || creature[which].species == MISSILE || creature[which].species == CLOUD || creature[which].species == LION)
  2024.             {   creature[which].alive = FALSE;
  2025.             } elif (creature[which].species == FRAGMENT)
  2026.             {   reflect(which);
  2027.         }   }
  2028.         elif (c == STONE || c == WOOD)
  2029.         {   if
  2030.             (   creature[which].species == DRIP
  2031.              || creature[which].species == FRAGMENT
  2032.              || creature[which].species == MISSILE
  2033.              || creature[which].species == CLOUD
  2034.              || creature[which].species == LION
  2035.              || creature[which].species == ORB
  2036.             )
  2037.             {   effect(FXDEATH_FRAGMENT);
  2038.                 creature[which].alive = FALSE;
  2039.         }   }
  2040.         elif (c == DYNAMITE)
  2041.         {   ;
  2042.         } elif (c >= FIRSTGRAVE && c <= LASTGRAVE)
  2043.         {   if (creature[which].species == ORB)
  2044.             {   effect(FXGET_SKULL);
  2045.             } elif (creature[which].species == FRAGMENT || creature[which].species == DRIP || creature[which].species == MISSILE || creature[which].species == CLOUD)
  2046.             {   effect(FXDEATH_FRAGMENT);
  2047.                 creature[which].alive = FALSE;
  2048.         }   }
  2049.         elif (c == TELEPORT)
  2050.         {   /* Drips, fragments, missiles, orbs, whirlwinds, dogs, clouds, otters */
  2051.             i = whichteleport(x, y);
  2052.             if (creature[which].species != OTTER && blocked(i, creature[which].deltax, creature[which].deltay))
  2053.                 creature[which].alive = FALSE;
  2054.             else
  2055.             {   effect(FXUSE_TELEPORT);
  2056.                 creature[which].x = teleport[level][partner(i)].x + creature[which].deltax;
  2057.                 creature[which].y = teleport[level][partner(i)].y + creature[which].deltay;
  2058.  
  2059.                 if (creature[which].species == ORB)
  2060.                 {   creature[which].x = xwrap(creature[which].x);
  2061.                     creature[which].y = ywrap(creature[which].y);
  2062.                 } else
  2063.                 {   if (!(valid(creature[which].x, creature[which].y)))
  2064.                         creature[which].alive = FALSE;
  2065.                     if (creature[which].species == FRAGMENT)
  2066.                         creature[which].last = SILVER;
  2067.         }   }   }
  2068.         elif (creature[which].species == ORB)
  2069.         {   if (c <= LASTOBJECT)
  2070.             {   if
  2071.                 (   c == AMMO
  2072.                  || c == CYCLONE
  2073.                  || c == LIGHTNING
  2074.                  || c == BRAKES
  2075.                  || c == POWER
  2076.                  || c == PULSE
  2077.                  || c == SLAYER
  2078.                  || c == SLOWER
  2079.                  || c == ENCLOSER
  2080.                 )
  2081.                 {   creature[which].speed = speedup(creature[which].speed, TRUE);
  2082.                 } elif (c == HEALER || c == LIFE || c == ICE || c == TREASURE || c == UMBRELLA || c == BONUS || c == ARMOUR)
  2083.                 {   orbsplit(which);
  2084.                 } else switch (c)
  2085.                 {
  2086.                 case BOMB:
  2087.                     draw(x, y, ORB);
  2088.                     bombblast(ORB, which, x, y);
  2089.                 break;
  2090.                 case PROTECTOR:
  2091.                     for (player = 0; player <= 3; player++)
  2092.                     {   if (worm[player].lives)
  2093.                         {   for (i = 0; i <= PROTECTORS; i++)
  2094.                             {  if (protector[player][i].alive)
  2095.                                {   protector[player][i].alive = FALSE;
  2096.                                    if (protector[player][i].visible)
  2097.                                    {   change(protector[player][i].x, protector[player][i].y, EMPTY);
  2098.                     }   }   }  }   }
  2099.                 break;
  2100.                 case MISSILE:
  2101.                 case CONVERTER:
  2102.                     effect(FXGET_OBJECT);
  2103.                     for (i = 0; i <= CREATURES; i++)
  2104.                     {   if (creature[i].alive && creature[i].species == MISSILE)
  2105.                         {   creature[i].alive = FALSE;
  2106.                             change(x, y, EMPTY);
  2107.                     }   }
  2108.                 break;
  2109.                 case MULTIPLIER:
  2110.                     effect(FXGET_OBJECT);
  2111.                     creature[which].multi *= 2;
  2112.                     if (creature[which].multi > MULTILIMIT)
  2113.                         creature[which].multi = MULTILIMIT;
  2114.                 break;
  2115.                 case BIAS:
  2116.                     effect(FXGET_OBJECT);
  2117.                     for (player = 0; player <= 3; player++)
  2118.                         if (worm[player].lives && worm[player].bias)
  2119.                         {   worm[player].bias = 0;
  2120.                             stat(player, BIAS);
  2121.                         }
  2122.                 break;
  2123.                 case AFFIXER:
  2124.                     effect(FXGET_OBJECT);
  2125.                     for (player = 0; player <= 3; player++)
  2126.                         if (worm[player].lives)
  2127.                         {   worm[player].affixer = FALSE;
  2128.                             icon(player, AFFIXER);
  2129.                         }
  2130.                 break;
  2131.                 case REMNANTS:
  2132.                     effect(FXGET_OBJECT);
  2133.                     for (player = 0; player <= 3; player++)
  2134.                         if (worm[player].lives)
  2135.                         {   worm[player].remnants = FALSE;
  2136.                             icon(player, REMNANTS);
  2137.                         }
  2138.                 break;
  2139.                 case SIDESHOT:
  2140.                     effect(FXGET_POWERUP);
  2141.                     for (player = 0; player <= 3; player++)
  2142.                         if (worm[player].lives)
  2143.                         {   worm[player].sideshot = FALSE;
  2144.                             icon(player, SIDESHOT);
  2145.                         }
  2146.                 break;
  2147.                 case MAGNET:
  2148.                     effect(FXGET_OBJECT);
  2149.                     for (i = 0; i <= MAGNETS; i++)
  2150.                         if (magnet[i].alive)
  2151.                             magnet[i].alive = FALSE;
  2152.                 break;
  2153.                 case PUSHER:
  2154.                     effect(FXGET_OBJECT);
  2155.                     for (i = 0; i <= 3; i++)
  2156.                         if (worm[i].lives && worm[i].pusher)
  2157.                         {   worm[i].pusher = FALSE;
  2158.                             icon(i, PUSHER);
  2159.                         }
  2160.                 break;
  2161.                 case GLOW:
  2162.                     effect(FXGET_OBJECT);
  2163.                     for (xx = 0; xx <= FIELDX; xx++)
  2164.                         for (yy = 0; yy <= FIELDY; yy++)
  2165.                             if (field[xx][yy] >= FIRSTGLOW && field[xx][yy] <= LASTGLOW)
  2166.                                 change(xx, yy, EMPTY);
  2167.                 break;
  2168.                 case SWITCHER:
  2169.                     effect(FXGET_OBJECT);
  2170.                     for (xx = 0; xx <= FIELDX; xx++)
  2171.                         for (yy = 0; yy <= FIELDY; yy++)
  2172.                             if (field[xx][yy] >= FIRSTTAIL && field[xx][yy] <= LASTTAIL)
  2173.                                 change(xx, yy, WOOD);
  2174.                 break;
  2175.                 case GROWER:
  2176.                     effect(FXGET_GROWER);
  2177.                     for (xx = 0; xx <= FIELDX; xx++)
  2178.                         for (yy = 0; yy <= FIELDY; yy++)
  2179.                             if (field[xx][yy] == WOOD)
  2180.                                 for (xxx = xx - 1; xxx <= xx + 1; xxx++)
  2181.                                     for (yyy = yy - 1; yyy <= yy + 1; yyy++)                                                                if (valid(xxx, yyy) && field[xxx][yyy] == EMPTY)
  2182.                                         field[xxx][yyy] = TEMPWOOD;
  2183.                     for (xx = 0; xx <= FIELDX; xx++)
  2184.                         for (yy = 0; yy <= FIELDY; yy++)
  2185.                             if (field[xx][yy] == TEMPWOOD)
  2186.                                 change(xx, yy, WOOD);
  2187.                 break;
  2188.                 case CLOCK:
  2189.                     secondsperlevel -= arand(RAND_CLOCK);
  2190.                     if (secondsperlevel < 0)
  2191.                         secondsperlevel = 0;
  2192.                 break;
  2193.                 case CUTTER:
  2194.                     for (i = 0; i <= 3; i++)
  2195.                         if (worm[i].lives && worm[i].cutter)
  2196.                         {   worm[i].cutter = 0;
  2197.                             icon(i, CUTTER);
  2198.                         }
  2199.                 break;
  2200.                 default:
  2201.                     // assert(0);
  2202.                 break;
  2203.     }   }   }   }
  2204.     
  2205.     x = creature[which].x; /* We refresh these in case a fragment has been */
  2206.     y = creature[which].y; /* reflected. Yes, it is vital. */
  2207.         
  2208.     if (creature[which].alive && creature[which].visible && (creature[which].deltax || creature[which].deltay))
  2209.     {   if (creature[which].species == MISSILE)
  2210.         {   drawmissile(x, y, which);
  2211.         } elif (creature[which].species == DRIP)
  2212.         {   change(x, y, FIRSTDRIP + creature[which].type);
  2213.         } else /* fragments, goats, penguins, cyclones, dogs, clouds, orbs, octopi, fish, otters */
  2214.         {   change(x, y, creature[which].species);
  2215.     }   }
  2216.     
  2217.     if (creature[which].alive)
  2218.     {   /* decide whether to fire */
  2219.         if (creature[which].species == GOAT)
  2220.         {   if (!arand(FREQ_GOATFIRE))
  2221.             {   for (i = 0; i <= CREATURES; i++)
  2222.                 {   if (!creature[i].alive)
  2223.                     {   deltax = arand(2) - 1;
  2224.                         deltay = arand(2) - 1;
  2225.                         if (valid(x + deltax, y + deltay) && (deltax || deltay))
  2226.                         {   c = field[x + deltax][y + deltay];
  2227.                             if
  2228.                             (   (c >= FIRSTEMPTY && c <= LASTEMPTY)
  2229.                              || (c >= FIRSTTAIL && c <= LASTTAIL)
  2230.                             )
  2231.                             {   effect(FXDO_GOAT);
  2232.                                 createcreature(FRAGMENT, i, x + deltax, y + deltay, deltax, deltay, 255);
  2233.                         }   }
  2234.                         break;
  2235.         }   }   }   }
  2236.         elif (creature[which].species == CLOUD)
  2237.         {   if (!arand(FREQ_CLOUDFIRE))
  2238.             {   cloudbullet(which, x, y, -1);
  2239.                 cloudbullet(which, x, y, 1);
  2240.         }   }
  2241.         elif (creature[which].species == OCTOPUS)
  2242.         {   if (creature[which].dir == -1)
  2243.             {   if (!arand(FREQ_OCTOPUSFIRE))
  2244.                 {   creature[which].dir = 0;
  2245. }   }   }   }   }
  2246.  
  2247. MODULE void cloudbullet(UBYTE which, SBYTE x, SBYTE y, SBYTE deltay)
  2248. {   UBYTE i, c;
  2249.  
  2250.     for (i = 0; i <= CREATURES; i++)
  2251.     {   if (!creature[i].alive)
  2252.         {   if (valid(x, y + deltay))
  2253.             {   c = field[x][y + deltay];
  2254.                 if
  2255.                 (   (c >= FIRSTEMPTY && c <= LASTEMPTY)
  2256.                 ||  (c >= FIRSTTAIL && c <= LASTTAIL)
  2257.                 )
  2258.                 {   effect(FXDO_CLOUD);
  2259.                     createcreature(FRAGMENT, i, x, y + deltay, 0, deltay, 255);
  2260.             }   }
  2261.             break;
  2262. }   }   }
  2263.  
  2264. MODULE void orbsplit(SBYTE which)
  2265. {   SBYTE copy = 0, i;
  2266.  
  2267.     effect(FXDO_ORB);
  2268.     for (i = 0; i <= CREATURES; i++)
  2269.     {   if (!creature[i].alive)
  2270.         {   creature[i].x       = creature[which].x;
  2271.             creature[i].y       = creature[which].y;
  2272.             creature[i].score   = creature[which].score;
  2273.             creature[i].speed   = creature[which].speed;
  2274.             creature[i].multi   = creature[which].multi;
  2275.             creature[i].last    = EMPTY;
  2276.             creature[i].species = ORB;
  2277.             switch (copy)
  2278.             {
  2279.             case 0:
  2280.                 if (creature[which].deltax != -1 || creature[which].deltay != -1)
  2281.                 {   creature[i].deltax = -1;
  2282.                     creature[i].deltay = -1;
  2283.                     creature[i].alive = TRUE;
  2284.                 }
  2285.             break;
  2286.             case 1:
  2287.                 if (creature[which].deltax != 1 || creature[which].deltay != 1)
  2288.                 {   creature[i].deltax = 1;
  2289.                     creature[i].deltay = 1;
  2290.                     creature[i].alive = TRUE;
  2291.                 }
  2292.             break;
  2293.             case 2:
  2294.                 if (creature[which].deltax != 1 || creature[which].deltay != -1)
  2295.                 {   creature[i].deltax = 1;
  2296.                     creature[i].deltay = -1;
  2297.                     creature[i].alive = TRUE;
  2298.                 }
  2299.             break;
  2300.             case 3:
  2301.                 if (creature[which].deltax != -1 || creature[which].deltay != 1)
  2302.                 {   creature[i].deltax = -1;
  2303.                     creature[i].deltay = 1;
  2304.                     creature[i].alive = TRUE;
  2305.                 }
  2306.             break;
  2307.             default:
  2308.             break;
  2309.             }
  2310.             if (++copy >= 4)
  2311.                 return;
  2312. }   }   }
  2313.  
  2314. SBYTE partner(SBYTE which)
  2315. {   if (which % 2 == 0)
  2316.         return((SBYTE) (which + 1));
  2317.     else return((SBYTE) (which - 1));
  2318. }
  2319.  
  2320. MODULE void putnumber(void)
  2321. {   SBYTE oldnumbery = numbery;
  2322.     ABOOL done;
  2323.  
  2324.     do
  2325.     {   done = findempty(&numberx, &numbery, FALSE);
  2326.     } while (!done);
  2327.     change(numberx, numbery, FIRSTLETTER + number - 1);
  2328.     updatearrow(oldnumbery);
  2329.     updatearrow(numbery);
  2330. }
  2331.  
  2332. /* NAME     queue -- adds a keystroke to the key queue
  2333. SYNOPSIS    name(SBYTE, SBYTE, SBYTE);
  2334. FUNCTION    Adds a keystroke to the in-game key queue.
  2335. INPUTS      player - player that pressed the key
  2336.             deltax - the deltax of the key
  2337.             deltay - the deltay of the key
  2338. IMPLEMENTATION
  2339.             thewormqueue[] array has WORMQUEUELIMIT as its last index.
  2340.             It is implemented as a FIFO stack rather than LIFO so that
  2341.             the keystrokes are processed in the correct order (that is,
  2342.             the order in which they were pressed). The oldest keystroke
  2343.             is always at index [0], the next oldest at [1], and so on
  2344.             upwards to the newest keystroke, at [worm[player].pos].
  2345.             Keystrokes are removed from the bottom of the array ([0]),
  2346.             and the rest of the array is shuffled down to fill the gap,
  2347.             so that the contents of [1] go to [0], the contents of [2]
  2348.             go to [1], etc. worm[player].pos is adjusted to always point
  2349.             to the newest entry, which is the 'end' of the queue.
  2350. MODULE      engine.c */
  2351.  
  2352. void wormqueue(SBYTE player, SBYTE deltax, SBYTE deltay)
  2353. {   if (worm[player].pos < WORMQUEUELIMIT)
  2354.     {   worm[player].pos++;
  2355.         thewormqueue[player][worm[player].pos].deltax = deltax;
  2356.         thewormqueue[player][worm[player].pos].deltay = deltay;
  2357. }   }
  2358.  
  2359. MODULE void dogqueue(SBYTE which, SBYTE deltax, SBYTE deltay)
  2360. {   if (creature[which].pos < DOGQUEUELIMIT)
  2361.     {   creature[which].pos++;
  2362.         thedogqueue[which][creature[which].pos].deltax = deltax;
  2363.         thedogqueue[which][creature[which].pos].deltay = deltay;
  2364.     } else
  2365.     {   creature[which].alive = FALSE;
  2366.         change(creature[which].x, creature[which].y, EMPTY);
  2367. }   }
  2368.  
  2369. MODULE void reflect(UBYTE which)
  2370. {   creature[which].deltax  = -creature[which].deltax;
  2371.     creature[which].deltay  = -creature[which].deltay;
  2372.     creature[which].x      +=  creature[which].deltax * 2;
  2373.     creature[which].y      +=  creature[which].deltay * 2;
  2374. }
  2375.  
  2376. ABOOL savefields(STRPTR fieldname)
  2377. {   SBYTE i, j;
  2378.     TEXT  IOBuffer[NAMELENGTH + 1];
  2379.  
  2380. #ifdef PLATFORM_IBM
  2381.     SBYTE x, y;
  2382.     UBYTE amigaboard[AMIGAFIELDX + 1][FIELDY + 1];
  2383. #endif
  2384.  
  2385.     matchteleports();
  2386.  
  2387.     if (!ZOpen(fieldname, TRUE))
  2388.     {   return FALSE;
  2389.     }
  2390.  
  2391.     /* write header */
  2392.  
  2393.     strcpy(IOBuffer, "FSET 7.2");
  2394.     IOBuffer[9] = levels;
  2395.     if (!ZWrite(IOBuffer, 10))
  2396.     {   ZClose();
  2397.         return FALSE;
  2398.     }
  2399.  
  2400.     /* write high score table */
  2401.  
  2402.     for (i = 0; i <= HISCORES; i++)
  2403.     {   IOBuffer[0]                                             =  hiscore[i].player;
  2404.         IOBuffer[1]                                             =  hiscore[i].level;
  2405.  
  2406.         IOBuffer[2]                                             =   hiscore[i].score / 16777216;
  2407.         IOBuffer[3]                                             =  (hiscore[i].score % 16777216) / 65536;
  2408.         IOBuffer[4]                                             = ((hiscore[i].score % 16777216) % 65536) / 256;
  2409.         IOBuffer[5]                                             = ((hiscore[i].score % 16777216) % 65536) % 256;
  2410.         if (!ZWrite(IOBuffer, 6))
  2411.         {   ZClose();
  2412.             return FALSE;
  2413.         }
  2414.  
  2415.         for (j = 0; j <= NAMELENGTH; j++)
  2416.             IOBuffer[j]                                         = hiscore[i].name[j];
  2417.         if (!ZWrite(IOBuffer, NAMELENGTH + 1))
  2418.         {   ZClose();
  2419.             return FALSE;
  2420.         }
  2421.         for (j = 0; j <= TIMELENGTH; j++)
  2422.             IOBuffer[j]                                             = hiscore[i].time[j];
  2423.         if (!ZWrite(IOBuffer, TIMELENGTH + 1))
  2424.         {   ZClose();
  2425.             return FALSE;
  2426.         }
  2427.         for (j = 0; j <= DATELENGTH; j++)
  2428.             IOBuffer[j]                                             = hiscore[i].date[j];
  2429.         if (!ZWrite(IOBuffer, DATELENGTH + 1))
  2430.         {   ZClose();
  2431.             return FALSE;
  2432.     }   }
  2433.  
  2434.     /* write level data */
  2435.  
  2436.     for (i = 0; i <= levels; i++)
  2437.     {   IOBuffer[0]                        = startx[i];
  2438.         IOBuffer[1]                        = starty[i];
  2439.         IOBuffer[2]                                             = teleport[i][0].alive;
  2440.         IOBuffer[3]                                             = teleport[i][0].x;
  2441.         IOBuffer[4]                                             = teleport[i][0].y;
  2442.         IOBuffer[5]                                             = teleport[i][1].alive;
  2443.         IOBuffer[6]                                             = teleport[i][1].x;
  2444.         IOBuffer[7]                                             = teleport[i][1].y;
  2445.  
  2446. #ifdef PLATFORM_IBM
  2447.         IOBuffer[0] -= 6;
  2448.         IOBuffer[3] -= 6;
  2449.         IOBuffer[6] -= 6;
  2450. #endif
  2451.  
  2452.         if (!ZWrite(IOBuffer, 8))
  2453.         {   ZClose();
  2454.             return FALSE;
  2455.         }
  2456.  
  2457. #ifdef PLATFORM_AMIGA
  2458.         if (!ZWrite((char *) &board[i][0][0], LEVELSIZE))
  2459.         {   ZClose();
  2460.             return FALSE;
  2461.         }
  2462. #endif
  2463. #ifdef PLATFORM_IBM
  2464.         for (x = 0; x <= AMIGAFIELDX; x++)
  2465.         {   for (y = 0; y <= FIELDY; y++)
  2466.             {   amigaboard[x][y] = board[i][x + 6][y];
  2467.         }   }
  2468.  
  2469.         if (!ZWrite((char *) &amigaboard[0][0], LEVELSIZE))
  2470.         {   ZClose();
  2471.             return FALSE;
  2472.         }
  2473. #endif
  2474.     }
  2475.  
  2476.     /* write version string */
  2477.  
  2478.     if (!ZWrite(VERSION, strlen(VERSION)))
  2479.     {   ZClose();
  2480.         return FALSE;
  2481.     }
  2482.  
  2483.     ZClose();
  2484.  
  2485.     if (clearthem)
  2486.         clearhiscores();
  2487.     modified = FALSE;
  2488.     return TRUE;
  2489. }
  2490.  
  2491. void saylevel(COLOUR colour)
  2492. {   TEXT mainstring[15] = "Level ", tempstring[4];
  2493.  
  2494.     if (level > 0)
  2495.     {   stci_d(&mainstring[6], level);
  2496.         strcat((char*) mainstring, " of ");
  2497.         stci_d(tempstring, levels);
  2498.         strcat((char*) mainstring, (char*) tempstring);
  2499.         say(mainstring, colour);
  2500.     } else
  2501.     {   if (a == FIELDEDIT)
  2502.         {   say("Bonus Level", colour);
  2503.         } elif (leveltype == TREASURE)
  2504.         {   say("Bonus Level: Treasury!", colour);
  2505.         } elif (leveltype == DRIP)
  2506.         {   say("Bonus Level: Drips!", colour);
  2507.         } else
  2508.         {   // assert(leveltype == PENGUIN);
  2509.             say("Bonus Level: Penguins!", colour);
  2510. }   }   }
  2511.  
  2512. MODULE SBYTE slowdown(SBYTE speed, ABOOL brakes)
  2513. {   speed *= 2;
  2514.     if (brakes)
  2515.     {   if (speed > VERYSLOW)
  2516.             speed = VERYSLOW;
  2517.     } elif (speed > SLOW)
  2518.         speed = SLOW;
  2519.     return(speed);
  2520. }
  2521.  
  2522. MODULE void slowloop(void)
  2523. {   SBYTE i, player, which, x, xx, y, yy;
  2524.     UBYTE c;
  2525.     ABOOL ok;
  2526.  
  2527.     if (ice)
  2528.     {   ice--;
  2529.     }
  2530.  
  2531.     /* decrement worm strength */
  2532.  
  2533.     for (player = 0; player <= 3; player++)
  2534.     {   if (worm[player].lives)
  2535.         {   if (worm[player].bias > 0)
  2536.             {   worm[player].bias--;
  2537.                 stat(player, BIAS);
  2538.             }
  2539.             if (worm[player].cutter > 0)
  2540.             {   worm[player].cutter--;
  2541.                 icon(player, CUTTER);
  2542.             }                
  2543.             if (worm[player].glow > 0)
  2544.             {   worm[player].glow--;
  2545.                 icon(player, GLOW);
  2546.             }
  2547.             if (worm[player].armour > 0)
  2548.             {   worm[player].armour--;
  2549.                 stat(player, ARMOUR);
  2550.     }   }   }
  2551.  
  2552.     /* blank out old causes */
  2553.  
  2554.     for (player = 0; player <= 3; player++)
  2555.     {   if (worm[player].lives > 0 && r > worm[player].causewait)
  2556.         {   drawcause(player, BLACK);
  2557.             worm[player].causewait = (ULONG) -1; /* most future time possible */
  2558.     }   }
  2559.  
  2560. if (!ice)
  2561. {   if (level)
  2562.     {   /* create goats */
  2563.         if
  2564.         (   (!arand(FREQ_GOAT))
  2565.         &&  findempty(&x, &y, TRUE)
  2566.         )
  2567.         {   for (i = 0; i <= CREATURES; i++)
  2568.             {   if (!creature[i].alive)
  2569.                 {   createcreature(GOAT, i, x, y, 0, 0, 255);
  2570.                     break;
  2571.         }   }   }
  2572.         /* create octopi */
  2573.         if
  2574.         (   (!arand(FREQ_OCTOPUS))
  2575.         &&  findempty(&x, &y, TRUE)
  2576.         )
  2577.         {   for (i = 0; i <= CREATURES; i++)
  2578.             {   if (!creature[i].alive)
  2579.                 {   createcreature(OCTOPUS, i, x, y, 0, 0, 255);
  2580.                     break;
  2581.         }   }   }
  2582.         /* create fish */
  2583.         if
  2584.         (   (!arand(FREQ_FISH))
  2585.         &&  findempty(&x, &y, TRUE)
  2586.         )
  2587.         {   for (i = 0; i <= CREATURES; i++)
  2588.             {   if (!creature[i].alive)
  2589.                 {   createcreature(FISH, i, x, y, 0, 0, 255);
  2590.                     break;
  2591.         }   }   }
  2592.         /* create orbs */
  2593.         if (!arand(FREQ_ORB) && findempty(&x, &y, FALSE))
  2594.         {   for (i = 0; i <= CREATURES; i++)
  2595.             {   if (!creature[i].alive)
  2596.                 {   createcreature(ORB, i, x, y, (arand(1) * 2) - 1, (arand(1) * 2) - 1, 255);
  2597.                     break;
  2598.         }   }   }
  2599.         /* create dogs */
  2600.         if (!arand(FREQ_DOG) && findempty(&x, &y, FALSE))
  2601.         {   for (i = 0; i <= CREATURES; i++)
  2602.             {   if (!(creature[i].alive))
  2603.                 {   createcreature(DOG, i, x, y, 0, 0, 255);
  2604.                     break;
  2605.         }   }   }
  2606.         /* create giraffes */
  2607.         if (!arand(FREQ_GIRAFFE) && findempty(&x, &y, FALSE))
  2608.         {   for (i = 0; i <= CREATURES; i++)
  2609.             {   if (!(creature[i].alive))
  2610.                 {   createcreature(GIRAFFE, i, x, y, 0, 0, 255);
  2611.                     break;
  2612.         }   }   }
  2613.         /* create lions */
  2614.         if (!arand(FREQ_LION) && findempty(&x, &y, FALSE))
  2615.         {   for (i = 0; i <= CREATURES; i++)
  2616.             {   if (!(creature[i].alive))
  2617.                 {   createcreature(LION, i, x, y, 0, 0, 255);
  2618.                     break;
  2619.         }   }   }
  2620.         /* create slime */
  2621.         if (!arand(FREQ_SLIME) && findempty(&x, &y, FALSE))
  2622.             change(x, y, SLIME);
  2623.         /* grow slime */
  2624.         if (!arand(FREQ_SLIMEGROW))
  2625.         {   for (x = 0; x <= FIELDX; x++)
  2626.                 for (y = 0; y <= FIELDY; y++)
  2627.                     if (field[x][y] == SLIME)
  2628.                         for (xx = x - 1; xx <= x + 1; xx++)
  2629.                             for (yy = y - 1; yy <= y + 1; yy++)
  2630.                                 if (valid(xx, yy) && field[xx][yy] == EMPTY && !arand(1))
  2631.                                     field[xx][yy] = TEMPSLIME;
  2632.             for (x = 0; x <= FIELDX; x++)
  2633.                 for (y = 0; y <= FIELDY; y++)
  2634.                     if (field[x][y] == TEMPSLIME)
  2635.                         change(x, y, SLIME);
  2636.         }
  2637.         /* create timebombs */
  2638.         if (!arand(FREQ_TIMEBOMB) && findempty(&x, &y, FALSE))
  2639.         {   for (i = 0; i <= CREATURES; i++)
  2640.             {   if (!(creature[i].alive))
  2641.                 {   createcreature(TIMEBOMB, i, x, y, 0, 0, 255);
  2642.                     break;
  2643.     }   }   }   }
  2644.  
  2645.     /* create drips */
  2646.     if
  2647.     (   ( level && !arand(FREQ_DRIP))
  2648.      || (!level && leveltype == DRIP && !arand(FREQ_DRIP / BONUSSPEEDUP))
  2649.     )
  2650.     {   x = arand(FIELDX);
  2651.         y = arand(2);
  2652.         c = field[x][y];
  2653.         if (c >= FIRSTEMPTY && c <= LASTEMPTY)
  2654.         {   for (i = 0; i <= CREATURES; i++)
  2655.             {   if (!creature[i].alive)
  2656.                 {   createcreature(DRIP, i, x, y, 0, 1, (UBYTE) ((r / 16) % 4));
  2657.                     break;
  2658.     }   }   }   }
  2659.     // create penguins
  2660.     if
  2661.     (   (   ( level && !arand(FREQ_PENGUIN))
  2662.          || (!level && leveltype == PENGUIN && !arand(FREQ_PENGUIN / BONUSSPEEDUP))
  2663.         )
  2664.      && findempty(&x, &y, FALSE)
  2665.     )
  2666.     {   for (i = 0; i <= CREATURES; i++)
  2667.         {   if (!(creature[i].alive))
  2668.             {   createcreature(PENGUIN, i, x, y, 0, 0, 255);
  2669.                 break;
  2670.     }   }   }
  2671.     // create birds
  2672.     if
  2673.     (  (level && !arand(FREQ_BIRD) && findempty(&x, &y, FALSE))
  2674.     )
  2675.     {   // check whether this location is far enough away from the worms
  2676.         ok = TRUE;
  2677.         for (i = 0; i <= 3; i++)
  2678.         {   if
  2679.             (   worm[i].lives
  2680.              && abs(worm[i].x - x) < DISTANCE_BIRD * 2
  2681.              && abs(worm[i].y - y) < DISTANCE_BIRD * 2
  2682.             )
  2683.             {   ok = FALSE;
  2684.                 break;
  2685.         }   }
  2686.         if (ok)
  2687.         {   for (i = 0; i <= CREATURES; i++)
  2688.             {   if (!(creature[i].alive))
  2689.                 {   createcreature(BIRD, i, x, y, 0, 0, 255);
  2690.                     break;
  2691.     }   }   }   }
  2692.     /* create clouds */
  2693.     if
  2694.     (   (   ( level && !arand(FREQ_CLOUD))
  2695.          || (!level && leveltype == CLOUD && !arand(FREQ_CLOUD / BONUSSPEEDUP))
  2696.         )
  2697.      && findempty(&x, &y, FALSE)
  2698.     )
  2699.     {   for (i = 0; i <= CREATURES; i++)
  2700.         {   if (!creature[i].alive)
  2701.             {   if (x < FIELDX / 2)
  2702.                 {   createcreature(CLOUD, i, x, y, -1, 0, 255);
  2703.                 } else
  2704.                 {   createcreature(CLOUD, i, x, y,  1, 0, 255);
  2705.                 }
  2706.                 break;
  2707.     }   }   }
  2708.  
  2709.     /* create objects */
  2710.     for (which = 0; which <= LASTOBJECT; which++)
  2711.         if (level || leveltype != TREASURE || which == TREASURE)
  2712.         {   if (!arand(object[which].freq) && findempty(&x, &y, FALSE))
  2713.                 change(x, y, which);
  2714.         } elif (!arand(object[which].freq / 10) && findempty(&x, &y, FALSE))
  2715.             change(x, y, which);
  2716.  
  2717.     /* create teleports */
  2718.     if (!arand(FREQ_TELEPORT)
  2719.     && !teleport[level][2].alive
  2720.     && findempty(&(teleport[level][2].x), &(teleport[level][2].y), FALSE)
  2721.     && findempty(&(teleport[level][3].x), &(teleport[level][3].y), FALSE)
  2722.     && (teleport[level][2].x != teleport[level][3].x || teleport[level][2].y != teleport[level][3].y))
  2723.     {   teleport[level][2].alive = TRUE;
  2724.         teleport[level][3].alive = TRUE;
  2725.         change(teleport[level][2].x, teleport[level][2].y, TELEPORT);
  2726.         change(teleport[level][3].x, teleport[level][3].y, TELEPORT);
  2727. }   }
  2728. }
  2729.  
  2730. MODULE SBYTE speedup(SBYTE speed, ABOOL brakes)
  2731. {   speed /= 2;
  2732.     if (speed < FAST)
  2733.         speed = FAST;
  2734.     return(speed);
  2735. }
  2736.  
  2737. MODULE void squareblast(SBYTE type, SBYTE player, UBYTE c, SBYTE x, SBYTE y, ABOOL cutter)
  2738. {   SBYTE which;
  2739.     UBYTE filler;
  2740.  
  2741.     if (type == HEAD && worm[player].bias && (!cutter))
  2742.     {   filler = DYNAMITE;
  2743.     } else filler = EMPTY;
  2744.  
  2745.     if (c <= LASTOBJECT)
  2746.     {   if (!cutter)
  2747.         {   change(x, y, filler);
  2748.     }   }
  2749.     elif ((c >= FIRSTTAIL && c <= LASTTAIL) || c == WOOD || c == SLIME)
  2750.     {   change(x, y, filler);
  2751.     } elif (c >= FIRSTHEAD && c <= LASTHEAD)
  2752.     {   if (!cutter && (type != HEAD || player != c - FIRSTHEAD))
  2753.         {   if (worm[c - FIRSTHEAD].armour == 0)
  2754.             {   worm[c - FIRSTHEAD].cause = BOMB;
  2755.                 worm[c - FIRSTHEAD].alive = FALSE;
  2756.                 if (type == HEAD)
  2757.                 {   worm[c - FIRSTHEAD].victor = player;
  2758.                 } else
  2759.                 {   worm[c - FIRSTHEAD].victor = -1;
  2760.             }   }
  2761.             else
  2762.             {   effect(FXUSE_ARMOUR);
  2763.     }   }   }
  2764.     elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
  2765.     {   which = whichcreature(x, y, MISSILE, 255);
  2766.         if (!cutter)
  2767.         {   if (type == HEAD)
  2768.             {   if (player != c - FIRSTMISSILE)
  2769.                 {   wormkillcreature(player, which);
  2770.                     change(x, y, filler);
  2771.         }   }   }
  2772.         else
  2773.         {   creature[which].alive = FALSE;
  2774.             change(x, y, filler);
  2775.     }    }
  2776.     elif (c >= FIRSTDRIP && c <= LASTDRIP)
  2777.     {   if (!cutter)
  2778.         {   which = whichcreature(x, y, DRIP, 255);
  2779.             if (type == HEAD)
  2780.             {   wormkillcreature(player, which);
  2781.             } else
  2782.             {   creature[which].alive = FALSE;
  2783.             }
  2784.             change(x, y, filler);
  2785.     }   }
  2786.     elif
  2787.     (   c == CLOUD
  2788.      || c == DOG
  2789.      || c == FISH
  2790.      || c == FRAGMENT
  2791.      || c == GIRAFFE
  2792.      || c == GOAT
  2793.      || c == LION
  2794.      || c == OCTOPUS
  2795.      || c == ORB
  2796.      || c == PENGUIN
  2797.      || c == WHIRLWIND
  2798.     )
  2799.     {   if (!cutter)
  2800.         {   which = whichcreature(x, y, c, 255);
  2801.             if (type == HEAD)
  2802.             {   wormkillcreature(player, which);
  2803.             } else
  2804.             {   creature[which].alive = FALSE;
  2805.             }
  2806.             change(x, y, filler);
  2807. }   }   }
  2808.  
  2809. void timeloop(void)
  2810. {   AUTO    TEXT  timedisplay[5] = {"#:##"};
  2811.     AUTO    UBYTE i;
  2812.     AUTO    SBYTE y;
  2813.     PERSIST ABOOL expired        = FALSE;
  2814.  
  2815.     secondsleft = atleast(secondsleft, 0);
  2816.     timedisplay[0] = 48 +  (secondsleft / 60);
  2817.     timedisplay[2] = 48 + ((secondsleft % 60) / 10);
  2818.     timedisplay[3] = 48 + ((secondsleft % 60) % 10);
  2819.  
  2820.     if (!level)
  2821.     {   say(timedisplay, worm[treasurer].colour);
  2822.         if (!secondsleft)
  2823.         {   level = reallevel + 1;
  2824.             secondsleft = SECONDSPERLEVEL;
  2825.             newlevel(treasurer);
  2826.     }   }
  2827.     elif (!secondsleft)
  2828.     {   if (!expired)
  2829.         {   effect(FXSIREN);
  2830.             say("Time expired!", WHITE);
  2831.             expired = TRUE;
  2832.  
  2833.             // create otters
  2834.             for (i = 0; i <= CREATURES; i++)
  2835.             {   if (!creature[i].alive)
  2836.                 {   for (y = 0; y <= FIELDY - 1; y++)
  2837.                     {   if (field[0][y] >= FIRSTEMPTY && field[0][y] <= LASTEMPTY)
  2838.                         {   createcreature(OTTER, i, 0,      y, 0,  1, 255);
  2839.                             break;
  2840.                     }   }
  2841.                     break;
  2842.             }   }
  2843.             for (i = 0; i <= CREATURES; i++)
  2844.             {   if (!creature[i].alive)
  2845.                 {   for (y = FIELDY; y >= 1; y--)
  2846.                     {   if (field[FIELDX][y] >= FIRSTEMPTY && field[FIELDX][y] <= LASTEMPTY)
  2847.                         {   createcreature(OTTER, i, FIELDX, y, 0, -1, 255);
  2848.                             break;
  2849.                     }   }
  2850.                     break;
  2851.     }   }   }   }
  2852.     else
  2853.     {   expired = FALSE;
  2854.         say(timedisplay, WHITE);
  2855. }   }
  2856.  
  2857. void train(SCANCODE scancode)
  2858. {   SBYTE x, y;
  2859.  
  2860.     switch(scancode)
  2861.     {
  2862.     case HELP:
  2863.         trainer = !trainer;
  2864.     break;
  2865.     case NUMERICSLASH:
  2866.         /* Complete the level. */
  2867.         if (trainer)
  2868.         {   trainer = FALSE;
  2869.             endoflevel();
  2870.         }
  2871.     break;
  2872.     case NUMERICASTERISK:
  2873.         /* field[][] dump, for debugging purposes. */
  2874.         if (trainer)
  2875.         {   trainer = FALSE;
  2876.             say("Field dump...", PURPLE);
  2877.             for (x = 0; x <= FIELDX; x++)
  2878.                 for (y = 0; y <= FIELDY; y++)
  2879.                     draw(x, y, field[x][y]);
  2880.             anykey(FALSE);
  2881.         }
  2882.         break;
  2883.     case NUMERICPLUS:
  2884.         if (trainer)
  2885.         {   trainer = FALSE;
  2886.             say("Trainer activated!", PURPLE);
  2887.             anykey(FALSE);
  2888.             if (worm[1].lives > 0)
  2889.             {   worm[1].lives = LIVESLIMIT;
  2890.                 stat(1, LIFE);
  2891.                 worm[1].armour = ARMOURLIMIT;
  2892.                 stat(1, ARMOUR);
  2893.                 worm[1].bias = BIASLIMIT;
  2894.                 stat(1, BIAS);
  2895.                 worm[1].ammo = AMMOLIMIT;
  2896.                 stat(1, AMMO);
  2897.                 worm[1].power = POWERLIMIT;
  2898.                 stat(1, POWER);
  2899.                 worm[1].brakes = TRUE;
  2900.                 stat(1, BRAKES);
  2901.                 worm[1].affixer = TRUE;
  2902.                 icon(1, AFFIXER);
  2903.                 worm[1].remnants = TRUE;
  2904.                 icon(1, REMNANTS);
  2905.                 worm[1].sideshot = TRUE;
  2906.                 icon(1, SIDESHOT);
  2907.                 worm[1].pusher = TRUE;
  2908.                 icon(1, PUSHER);
  2909.                 worm[1].cutter = 100;
  2910.                 icon(1, CUTTER);
  2911.                 worm[1].encloser = TRUE;
  2912.                 icon(1, ENCLOSER);
  2913.                 trainer = FALSE;
  2914.         }   }
  2915.     break;
  2916.     default:
  2917.     break;
  2918. }   }
  2919.  
  2920. MODULE void turnworm(SBYTE player, SBYTE deltax, SBYTE deltay)
  2921. {   if (worm[player].deltax == deltax && worm[player].deltay == deltay)
  2922.     {   worm[player].speed = speedup(worm[player].speed, worm[player].brakes);
  2923.         stat(player, BRAKES);
  2924.     } elif (worm[player].deltax == -deltax && worm[player].deltay == -deltay)
  2925.     {   worm[player].speed = slowdown(worm[player].speed, worm[player].brakes);
  2926.         stat(player, BRAKES);
  2927.     } else
  2928.     {   worm[player].deltax = deltax;
  2929.         worm[player].deltay = deltay;
  2930. }   }
  2931.  
  2932. SBYTE valid(SBYTE x, SBYTE y)
  2933. {   if (x >= 0 && x <= FIELDX && y >= 0 && y <= FIELDY)
  2934.         return(TRUE);
  2935.     else return(FALSE);
  2936. }
  2937.  
  2938. MODULE UBYTE whichcreature(SBYTE x, SBYTE y, UBYTE species, UBYTE exception)
  2939. {   UBYTE i;    
  2940.  
  2941.     for (i = 0; i <= CREATURES; i++)
  2942.         if
  2943.         (   creature[i].alive
  2944.          && creature[i].x == x
  2945.          && creature[i].y == y
  2946.          && creature[i].species == species
  2947.          && i != exception
  2948.         )
  2949.             return i;
  2950.     return 255; /* error code */
  2951. }
  2952. MODULE SBYTE whichteleport(SBYTE x, SBYTE y)
  2953. {   SBYTE which;
  2954.  
  2955.     for (which = 0; which <= 3; which++)
  2956.         if (teleport[level][which].alive && teleport[level][which].x == x && teleport[level][which].y == y)
  2957.             return((SBYTE) which);
  2958.     return((SBYTE) -1); /* error code */
  2959. }
  2960.  
  2961. MODULE void wormbullet(SBYTE player)
  2962. {   ABOOL finished,
  2963.           ok,
  2964.           flag     = FALSE,
  2965.           lettered = FALSE;
  2966.     SBYTE distance,
  2967.           i, j,
  2968.           x, y;
  2969.     UBYTE c;
  2970.  
  2971.     if (!worm[player].ammo)
  2972.     {   stat(player, BONUS);
  2973.     if (worm[player].speed == FAST)
  2974.             distance = DISTANCE_FAST;
  2975.     elif (worm[player].speed == NORMAL)
  2976.            distance = DISTANCE_NORMAL;
  2977.         elif (worm[player].speed == SLOW)
  2978.            distance = DISTANCE_SLOW;
  2979.         else
  2980.         {  // assert(worm[player].speed == VERYSLOW);
  2981.            distance = DISTANCE_VERYSLOW;
  2982.         }
  2983.  
  2984.     /* check for metal */
  2985.  
  2986.     for (i = 1; i < distance; i++)
  2987.     {   x = xwrap(worm[player].x + (i * worm[player].deltax));
  2988.         y = ywrap(worm[player].y + (i * worm[player].deltay));
  2989.         if (field[x][y] == METAL)
  2990.         flag = TRUE;
  2991.     }
  2992.  
  2993.     if (!flag)
  2994.         {   // assert(abs(worm[player].deltax) <= 1 && abs(worm[player].deltay) <= 1);
  2995.         x = xwrap(worm[player].x + (worm[player].deltax * distance));
  2996.         y = ywrap(worm[player].y + (worm[player].deltay * distance));
  2997.             c = field[x][y];
  2998.             ok = TRUE;
  2999.             if (c == TELEPORT)
  3000.             {   ok = FALSE;
  3001.                 i = whichteleport(x, y);
  3002.             if (!blocked(i, worm[player].deltax, worm[player].deltay))
  3003.             ok = TRUE;
  3004.             } elif (c >= FIRSTGLOW && c <= LASTGLOW)
  3005.             {   if (player != c - FIRSTGLOW)
  3006.                 {   ok = FALSE;
  3007.             }   }
  3008.             if (ok && c != STONE && c != GOAT && c != METAL && c != OCTOPUS)
  3009.             {   effect(FXDO_JUMP);
  3010.             worm[player].deltax *= distance;
  3011.             worm[player].deltay *= distance;
  3012.     }   }   }
  3013.     else
  3014.     {   effect(FXUSE_AMMO);
  3015.         worm[player].ammo--;
  3016.         stat(player, AMMO);
  3017.         if (worm[player].sideshot)
  3018.         {   bullet[7].alive      = bullet[8].alive      = TRUE;
  3019.             bullet[7].teleported = bullet[8].teleported = 0;
  3020.             bullet[7].visible    = bullet[8].visible    = TRUE;
  3021.             bullet[7].reflected  = bullet[8].reflected  = FALSE;
  3022.             bullet[7].x          = bullet[8].x          = worm[player].x;
  3023.             bullet[7].y          = bullet[8].y          = worm[player].y;
  3024.             if (!worm[player].deltax && worm[player].deltay)
  3025.             {   bullet[7].deltax = -1;
  3026.                 bullet[8].deltax = 1;
  3027.                 bullet[7].deltay = bullet[8].deltay = 0;
  3028.             } elif (worm[player].deltax && !worm[player].deltay)
  3029.             {   bullet[7].deltax = bullet[8].deltax = 0;
  3030.                 bullet[7].deltay = -1;
  3031.                 bullet[8].deltay = 1;
  3032.             } else /* worm is diagonal */
  3033.             {   if (worm[player].deltax == worm[player].deltay)
  3034.                 {   bullet[7].deltax = 1;
  3035.                     bullet[7].deltay = -1;
  3036.                 } else
  3037.                 {   bullet[7].deltax = -1;
  3038.                     bullet[7].deltay = -1;
  3039.                 }
  3040.                 bullet[8].deltax = -bullet[7].deltax;
  3041.                 bullet[8].deltay = -bullet[7].deltay;
  3042.         }   }
  3043.  
  3044.         for (i = 0; i <= worm[player].power; i++)
  3045.         {   bullet[i].alive      = TRUE;
  3046.             bullet[i].teleported = 0;
  3047.             bullet[i].visible    = TRUE;
  3048.             bullet[i].reflected  = FALSE;
  3049.             bullet[i].deltax     = worm[player].deltax;
  3050.             bullet[i].deltay     = worm[player].deltay;
  3051.             if (i % 2 == 0)
  3052.                 distance = i / 2;
  3053.             else distance = -((i + 1) / 2);
  3054.             if (worm[player].deltax == 0)
  3055.             {   bullet[i].x = worm[player].x + distance;
  3056.                 bullet[i].y = worm[player].y;
  3057.             } elif (worm[player].deltay == 0)
  3058.             {   bullet[i].x = worm[player].x;
  3059.                 bullet[i].y = worm[player].y + distance;
  3060.             } else
  3061.             {   switch (i)
  3062.                 {
  3063.                 case 0:
  3064.                     bullet[i].x = worm[player].x + worm[player].deltax;
  3065.                     bullet[i].y = worm[player].y + worm[player].deltay;
  3066.                 break;
  3067.                 case 1:
  3068.                     bullet[i].x = worm[player].x + worm[player].deltax;
  3069.                     bullet[i].y = worm[player].y;
  3070.                 break;
  3071.                 case 2:
  3072.                     bullet[i].x = worm[player].x;
  3073.                     bullet[i].y = worm[player].y + worm[player].deltay;
  3074.                 break;
  3075.                 case 3:
  3076.                     bullet[i].x = worm[player].x + worm[player].deltax * 2;
  3077.                     bullet[i].y = worm[player].y;
  3078.                 break;
  3079.                 case 4:
  3080.                     bullet[i].x = worm[player].x;
  3081.                     bullet[i].y = worm[player].y + worm[player].deltay * 2;
  3082.                 break;
  3083.                 case 5:
  3084.                     bullet[i].x = worm[player].x + worm[player].deltax * 2;
  3085.                     bullet[i].y = worm[player].y - worm[player].deltay;
  3086.                 break;
  3087.                 case 6:
  3088.                     bullet[i].x = worm[player].x - worm[player].deltax;
  3089.                     bullet[i].y = worm[player].y + worm[player].deltay * 2;
  3090.                 break;
  3091.                 default:
  3092.                 break;
  3093.         }   }   }
  3094.  
  3095.         /* Bullets are now set up. */
  3096.  
  3097.         finished = FALSE;
  3098.         while (!finished)
  3099.         {   finished = TRUE;
  3100.             for (i = 0; i <= 8; i++)
  3101.             {   if (bullet[i].alive)
  3102.                 {   if (bullet[i].visible)
  3103.                     {   if (worm[player].remnants)
  3104.                             change(bullet[i].x, bullet[i].y, FIRSTGLOW + player);
  3105.                         else change(bullet[i].x, bullet[i].y, EMPTY);
  3106.                     }
  3107.  
  3108.                     finished = FALSE;
  3109.                     bullet[i].visible = TRUE;
  3110.                     if (bullet[i].reflected)
  3111.                     {   bullet[i].x -= bullet[i].deltax;
  3112.                         bullet[i].y -= bullet[i].deltay;
  3113.                     } else
  3114.                     {   bullet[i].x += bullet[i].deltax;
  3115.                         bullet[i].y += bullet[i].deltay;
  3116.                     }
  3117.                     x = bullet[i].x;
  3118.                     y = bullet[i].y;
  3119.                     c = field[x][y];
  3120.                     if (!(valid(x, y)))
  3121.                         bullet[i].alive = FALSE;
  3122.                     elif (x == worm[player].x && y == worm[player].y)
  3123.                     {   /* hit by own bullet */
  3124.                         bullet[i].alive = FALSE;
  3125.                         if (worm[player].armour == 0)
  3126.                         {   worm[player].cause = FIRSTFIRE + player;
  3127.                             worm[player].victor = -1;
  3128.                             worm[player].alive = FALSE;
  3129.                     }   }
  3130.                     elif (c >= FIRSTHEAD && c <= LASTHEAD)
  3131.                     {   if (worm[c - FIRSTHEAD].armour == 0)
  3132.                         {   worm[c - FIRSTHEAD].cause = FIRSTFIRE + player;
  3133.                             worm[c - FIRSTHEAD].victor = player;
  3134.                             worm[c - FIRSTHEAD].alive = FALSE;
  3135.                         } else effect(FXUSE_ARMOUR);
  3136.                         bullet[i].alive = FALSE;
  3137.                     } elif (c >= FIRSTPROTECTOR && c <= LASTPROTECTOR)
  3138.                     {   if (player != c - FIRSTPROTECTOR)
  3139.                         {   effect(FXUSE_PROTECTOR);
  3140.                             bullet[i].alive = FALSE;
  3141.                         } else bullet[i].visible = FALSE;
  3142.                     } elif (c >= FIRSTLETTER && c <= LASTLETTER)
  3143.                     {   getnumber(player);
  3144.                         lettered = TRUE;
  3145.                     } elif (c >= FIRSTGRAVE && c <= LASTGRAVE)
  3146.                     {   bullet[i].alive = FALSE;
  3147.                     } elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
  3148.                     {   if (player != c - FIRSTMISSILE)
  3149.                             creature[whichcreature(x, y, MISSILE, 255)].alive = FALSE;
  3150.                         else bullet[i].visible = FALSE;
  3151.                     } elif (c >= FIRSTDRIP && c <= LASTDRIP)
  3152.                     {   j = whichcreature(x, y, DRIP, 255);
  3153.                         creature[j].alive = FALSE;
  3154.                     } else
  3155.                     {   switch(c)
  3156.                         {
  3157.                         case BOMB:
  3158.                             // sets it off, for your benefit
  3159.                             bullet[i].alive = FALSE;
  3160.                             bombblast(HEAD, player, x, y);
  3161.                         break;
  3162.                         case SLIME:
  3163.                         case WOOD:
  3164.                             // destroys one layer of it
  3165.                             bullet[i].alive = FALSE;
  3166.                             change(x, y, EMPTY);
  3167.                         break;
  3168.                         case METAL:
  3169.                             if (bullet[i].reflected)
  3170.                                 bullet[i].alive = FALSE;
  3171.                             else
  3172.                             {   bullet[i].reflected = TRUE;
  3173.                                 bullet[i].x -= bullet[i].deltax * 2;
  3174.                                 bullet[i].y -= bullet[i].deltay * 2;
  3175.                             }
  3176.                             break;
  3177.                         case STONE:
  3178.                             bullet[i].alive = FALSE;
  3179.                         break;
  3180.                         case TELEPORT:
  3181.                             j = whichteleport(bullet[i].x, bullet[i].y);
  3182.                             if (bullet[i].teleported == 2)
  3183.                                 bullet[i].alive = FALSE;
  3184.                             else
  3185.                             {   effect(FXUSE_TELEPORT);
  3186.                                 bullet[i].visible = FALSE;
  3187.                                 bullet[i].teleported++;
  3188.                                 bullet[i].x = teleport[level][partner(j)].x;
  3189.                                 bullet[i].y = teleport[level][partner(j)].y;
  3190.                             }
  3191.                         break;
  3192.                         case CLOUD:
  3193.                         case DOG:
  3194.                         case FISH:
  3195.                         case FRAGMENT:
  3196.                         case GOAT:
  3197.                         case OCTOPUS:
  3198.                         case ORB:
  3199.                         case PENGUIN:
  3200.                         case WHIRLWIND:
  3201.                             bullet[i].alive = FALSE;
  3202.                             j = whichcreature(x, y, c, 255);
  3203.                             wormkillcreature(player, j);
  3204.                             change(x, y, EMPTY);
  3205.                         break;
  3206.                         case TIMEBOMB:
  3207.                             bullet[i].alive = FALSE;
  3208.                             creature[whichcreature(x, y, TIMEBOMB, 255)].alive = FALSE;
  3209.                             bombblast(BOMB, 0, x, y);
  3210.                             change(x, y, EMPTY);
  3211.                         break;
  3212.                         default:
  3213.                         break;
  3214.                     }   }
  3215.  
  3216.                     // x and y need this refreshing here
  3217.                     x = bullet[i].x;
  3218.                     y = bullet[i].y;
  3219.                     if (bullet[i].alive && bullet[i].visible)
  3220.                     {   draw(x, y, FIRSTFIRE + player);
  3221.         }   }   }   }
  3222.         if (lettered)
  3223.         {   putnumber();
  3224.         }
  3225.         clearkybd();
  3226. }   }
  3227.  
  3228. /* NAME     wormloop -- controls worms and protectors
  3229. SYNOPSIS    wormloop(SBYTE);
  3230. FUNCTION    Amiga-worm thinking, processing one keystroke from the
  3231.             worm's queue, all the worm's protectors' control, the
  3232.             worm's control.
  3233. MODULE      engine.c */
  3234.  
  3235. MODULE void wormloop(SBYTE player)
  3236. {   SBYTE bestx = 0, besty = 0, // to avoid spurious warnings
  3237.           dirx, diry, i, j, thisprot, x, y, index1, index2;
  3238.     SWORD bestgood, good;
  3239.     UBYTE c;
  3240.  
  3241.    /*  Amiga worm control
  3242.        Remove a keystroke from the worm queue
  3243.        Move worm (and add a keystroke to the dog queue)
  3244.        Check for enclosure
  3245.        Move protectors
  3246.        Collision detection
  3247.  
  3248.     AI: Amiga worm control.
  3249.  
  3250.     Worm checks ahead, left and right one square. Assigns opinions
  3251.     to those three choices and then takes the appropriate one.
  3252.  
  3253.     Things which slow the worm down are doubly feared; this is to avoid
  3254.     endless ramming situations. */
  3255.  
  3256.     if (worm[player].control == AMIGA)
  3257.     {   if (!arand(50))
  3258.             wormqueue(player, arand(2) - 1, arand(2) - 1);
  3259.         else
  3260.         {   bestgood = -128;
  3261.  
  3262.             for (i = 0; i <= 2; i++)
  3263.             {   switch(i)
  3264.                 {
  3265.                 case 0:
  3266.                     dirx = worm[player].deltax;
  3267.                     diry = worm[player].deltay;
  3268.                 break;
  3269.                 case 1:
  3270.                     if (worm[player].deltax == 0) /* if going north or south */
  3271.                     {   dirx = -1;                /* then look west */
  3272.                         diry = 0;
  3273.                     } else                        /* if going east or west */
  3274.                     {   dirx = 0;                 /* then look north */
  3275.                         diry = -1;
  3276.                     }
  3277.                 break;
  3278.                 case 2:
  3279.                     if (worm[player].deltax == 0) /* if going north or south */
  3280.                     {   dirx = 1;                 /* then look east */
  3281.                         diry = 0;
  3282.                     } else                        /* if going east or west */
  3283.                     {   dirx = 0;                 /* then look south */
  3284.                         diry = 1;
  3285.                     }
  3286.                 break;
  3287.                 default:
  3288.                     dirx = diry = 0; // to prevent spurious warnings
  3289.                 break;
  3290.                 }
  3291.                 c = field[xwrap(worm[player].x + dirx)][ywrap(worm[player].y + diry)];
  3292.                 if (c >= FIRSTLETTER && c <= LASTLETTER)
  3293.                     good = POINTS_LETTER;
  3294.                 elif (c >= FIRSTHEAD && c <= LASTHEAD)
  3295.                     good = -(PAIN_HEAD);
  3296.                 elif (c <= LASTOBJECT)
  3297.                     good = (SWORD) object[c].score;
  3298.                 elif (c == FIRSTPROTECTOR + player)
  3299.                     good = POINTS_EMPTY;
  3300.                 elif (c >= FIRSTGLOW && c <= LASTGLOW)
  3301.                 {   if (player == c - FIRSTGLOW)
  3302.                 good = -1;
  3303.                     else good = -(PAIN_GLOW);
  3304.                 } elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
  3305.                 {   if (player == c - FIRSTMISSILE)
  3306.                         good = 0;
  3307.                     else good = -(PAIN_MISSILE);
  3308.                 } elif (c >= FIRSTDRIP && c <= LASTDRIP)
  3309.                 {   if (player == c - FIRSTDRIP)
  3310.                         good = SCORE_DRIP;
  3311.                     else good = -(PAIN_DRIP);
  3312.                 } elif (c >= FIRSTGRAVE && c <= LASTGRAVE)
  3313.                 {   good = POINTS_GRAVE;
  3314.                 } elif (c >= FIRSTTAIL && c <= LASTTAIL)
  3315.                 {   if (worm[player].armour > 10)
  3316.                         if (player != c - FIRSTTAIL)
  3317.                             good = POINTS_TURNSILVER;
  3318.                         else good = 0;
  3319.                     elif (player == c - FIRSTTAIL)
  3320.                         good = -(PAIN_FRIENDLYTAIL);
  3321.                     else good = -(PAIN_ENEMYTAIL);
  3322.                 } else switch(c)
  3323.                 {
  3324.                 case GOLD:
  3325.                     good = POINTS_GOLD;
  3326.                 break;
  3327.                 case SILVER:
  3328.                     good = POINTS_SILVER;
  3329.                 break;
  3330.                 case EMPTY:
  3331.                     good = POINTS_EMPTY;
  3332.                 break;
  3333.                 case SLIME:
  3334.                     if (worm[player].armour > 0)
  3335.                         good = 0;
  3336.                     else good = -(PAIN_SLIME);
  3337.                 break;
  3338.                 case WOOD:
  3339.                     if (worm[player].armour > 0)
  3340.                         good = 0;
  3341.                     else good = -(PAIN_WOOD);
  3342.                 break;
  3343.                 case STONE:
  3344.                     good = -(PAIN_STONE * 2);
  3345.                 break;
  3346.                 case METAL:
  3347.                     good = -(PAIN_METAL * 2);
  3348.                 break;
  3349.                 case GOAT:
  3350.                     good = -(PAIN_GOAT * 2);
  3351.                 break;
  3352.                 case CLOUD:
  3353.                     good = -(PAIN_CLOUD);
  3354.                 break;
  3355.                 case DOG:
  3356.                     good = -(PAIN_DOG);
  3357.                 break;
  3358.                 case FISH:
  3359.                     good = -(PAIN_FISH);
  3360.                 break;
  3361.                 case FRAGMENT:
  3362.                     good = -(PAIN_FRAGMENT);
  3363.                 break;
  3364.                 case GIRAFFE:
  3365.                     good = -(PAIN_GIRAFFE);
  3366.                 break;
  3367.                 case LION:
  3368.                     good = -(PAIN_LION);
  3369.                 break;
  3370.                 case OCTOPUS:
  3371.                     good = -(PAIN_OCTOPUS * 2);
  3372.                 break;
  3373.                 case ORB:
  3374.                     good = -(PAIN_ORB);
  3375.                 break;
  3376.                 case WHIRLWIND:
  3377.                     good = -(PAIN_WHIRLWIND);
  3378.                 break;
  3379.                 default:
  3380.                     good = 0;
  3381.                 break;
  3382.                 }
  3383.                 if (good > bestgood)
  3384.                 {   bestx = dirx;
  3385.                     besty = diry;
  3386.                     bestgood = good;
  3387.             }   }
  3388.             if (bestgood < -2 && !arand(1))
  3389.             {   // turn in any of the 8 directions, or fire
  3390.                 wormqueue
  3391.                 (   player,
  3392.                     (SBYTE) ((arand(1) * 2) - 1),
  3393.                     (SBYTE) ((arand(1) * 2) - 1)
  3394.                 );
  3395.             }
  3396.             elif (bestgood < -1 && !arand(1))
  3397.                 wormqueue(player, 0, 0);
  3398.             elif (bestgood < 0 && !arand(5))
  3399.                 wormqueue(player, 0, 0);
  3400.             elif (bestx != worm[player].deltax || besty != worm[player].deltay)
  3401.                 wormqueue(player, bestx, besty);
  3402.     }   }
  3403.  
  3404.     /* remove a keystroke from the worm queue */
  3405.  
  3406.     if (worm[player].pos != -1)                         
  3407.     {   if (first && worm[2].lives && worm[2].control == JOYSTICK)
  3408.         {   first = FALSE;
  3409.             /* Yes, this is defensive programming :-(
  3410.             Because the first time the blue worm has joystick control, a
  3411.             bizarre firebutton event seems to occur. */
  3412.         } else
  3413.         {   if (thewormqueue[player][0].deltax == 0 && thewormqueue[player][0].deltay == 0)
  3414.                 wormbullet(player);
  3415.             else
  3416.             {   if (!worm[player].frosted)
  3417.                 {   turnworm(player, thewormqueue[player][0].deltax, thewormqueue[player][0].deltay);
  3418.         }   }   }
  3419.         if (--worm[player].pos != -1)
  3420.         {   for (i = 0; i <= worm[player].pos; i++)
  3421.             {   thewormqueue[player][i].deltax = thewormqueue[player][i + 1].deltax;
  3422.                 thewormqueue[player][i].deltay = thewormqueue[player][i + 1].deltay;
  3423.     }   }   }
  3424.     worm[player].frosted = FALSE;
  3425.  
  3426.     /* move worm */
  3427.  
  3428.     if (worm[player].last == FIRSTTAIL + player)
  3429.     {   field[worm[player].x][worm[player].y] = FIRSTTAIL + player;
  3430.         if (!thick)
  3431.         {   index1 =       worm[player].olddeltax + 1 + (      (worm[player].olddeltay + 1) * 3);
  3432.             index2 = bsign(worm[player].deltax)   + 1 + ((bsign(worm[player].deltay)   + 1) * 3);
  3433.             drawtail(worm[player].x, worm[player].y, eachtail[player][0][index1][index2]);
  3434.         } else
  3435.         {   draw(worm[player].x, worm[player].y, FIRSTTAIL + player);
  3436.     }   }
  3437.     elif (worm[player].last == FIRSTGLOW + player)
  3438.     {   field[worm[player].x][worm[player].y] = FIRSTGLOW + player;
  3439.         if (!thick)
  3440.         {   index1 =       worm[player].olddeltax + 1 + (      (worm[player].olddeltay + 1) * 3);
  3441.             index2 = bsign(worm[player].deltax)   + 1 + ((bsign(worm[player].deltay)   + 1) * 3);
  3442.             drawtail(worm[player].x, worm[player].y, eachtail[player][1][index1][index2]);
  3443.         } else
  3444.         {   draw(worm[player].x, worm[player].y, FIRSTGLOW + player);
  3445.     }   }
  3446.     else
  3447.     {   change(worm[player].x, worm[player].y, worm[player].last);
  3448.     }
  3449.  
  3450.     worm[player].x = xwrap(worm[player].x + worm[player].deltax);
  3451.     worm[player].y = ywrap(worm[player].y + worm[player].deltay);
  3452.  
  3453.     if (worm[player].glow)
  3454.     {   worm[player].last = FIRSTGLOW + player;
  3455.     } else
  3456.     {   worm[player].last = FIRSTTAIL + player;
  3457.     }
  3458.  
  3459.     for (i = 0; i <= CREATURES; i++)
  3460.     {   if (creature[i].alive && creature[i].species == DOG && creature[i].dormant > DORMANT && creature[i].type == player)
  3461.         {   if (!worm[player].rammed)
  3462.                 dogqueue(i, worm[player].deltax, worm[player].deltay);
  3463.             if (creature[i].dormant < CHASING)
  3464.             {   creature[i].dormant++;
  3465.                 draw(creature[i].x, creature[i].y, DOGAWAKENING);
  3466.     }   }   }
  3467.  
  3468.     /* The deltas are not changed back to the range of -1..1 until after
  3469.     the dogs have looked at the queue. This enables them to jump properly. */
  3470.  
  3471.     worm[player].rammed = FALSE;
  3472.     worm[player].deltax = bsign(worm[player].deltax);
  3473.     worm[player].deltay = bsign(worm[player].deltay);
  3474.     worm[player].olddeltax = worm[player].deltax;
  3475.     worm[player].olddeltay = worm[player].deltay;
  3476.  
  3477.     /*  check for enclosure
  3478.         #####
  3479.         #...#
  3480.         #...# . = interior
  3481.         #...# # = tail
  3482.         ####! ! = head */
  3483.  
  3484.     enclosed = FALSE;
  3485.     for (i = 2; i <= 10; i++) // for each size of interior
  3486.     {   for (j = 0; j <= 3; j++) // four times, once for each direction
  3487.         {   checkrectangle(j, player, i, i);
  3488.             if (worm[player].encloser)
  3489.             {   checkrectangle(j, player, i, i + 1);
  3490.                 checkrectangle(j, player, i + 1, i);
  3491.     }   }   }
  3492.  
  3493.     // move protectors
  3494.  
  3495.     for (i = 0; i <= PROTECTORS; i++)
  3496.     {   if (protector[player][i].alive)
  3497.         {   if (protector[player][i].visible)
  3498.             {   change(protector[player][i].x, protector[player][i].y, protector[player][i].last);
  3499.             } else protector[player][i].visible = TRUE;
  3500.             protector[player][i].last = EMPTY;
  3501.             if (i == NOSE)
  3502.             {   protector[player][i].relx = worm[player].deltax * DISTANCE_NOSE;
  3503.                 protector[player][i].rely = worm[player].deltay * DISTANCE_NOSE;
  3504.                 if (!worm[player].affixer)
  3505.                 {   if (worm[player].position == -1)
  3506.                         worm[player].posidir = 1;
  3507.                     elif (worm[player].position == 1)
  3508.                         worm[player].posidir = -1;
  3509.                     worm[player].position += worm[player].posidir;
  3510.                     if (worm[player].deltax == 0)
  3511.                         protector[player][i].relx = worm[player].position;
  3512.                     elif (worm[player].deltay == 0)
  3513.                         protector[player][i].rely = worm[player].position;
  3514.                     elif (worm[player].position == -1)
  3515.                         protector[player][i].relx = worm[player].deltax * (DISTANCE_NOSE - 1);
  3516.                     elif (worm[player].position == 1)
  3517.                         protector[player][i].rely = worm[player].deltay * (DISTANCE_NOSE - 1);
  3518.             }   }
  3519.             elif (!worm[player].affixer)
  3520.             {   if (protector[player][i].relx == 1 && protector[player][i].rely == -1)
  3521.                 {   protector[player][i].deltax = 0;
  3522.                     protector[player][i].deltay = 1;
  3523.                 } elif (protector[player][i].relx == 1 && protector[player][i].rely == 1)
  3524.                 {   protector[player][i].deltax = -1;
  3525.                     protector[player][i].deltay = 0;
  3526.                 } elif (protector[player][i].relx == -1 && protector[player][i].rely == 1)
  3527.                 {   protector[player][i].deltax = 0;
  3528.                     protector[player][i].deltay = -1;
  3529.                 } elif (protector[player][i].relx == -1 && protector[player][i].rely == -1)
  3530.                 {   protector[player][i].deltax = 1;
  3531.                     protector[player][i].deltay = 0;
  3532.                 }
  3533.                 protector[player][i].relx += protector[player][i].deltax;
  3534.                 protector[player][i].rely += protector[player][i].deltay;
  3535.             }
  3536.             protector[player][i].x = worm[player].x + protector[player][i].relx;
  3537.             protector[player][i].y = worm[player].y + protector[player][i].rely;
  3538.             if (!valid(protector[player][i].x, protector[player][i].y))
  3539.             {   protector[player][i].visible = FALSE;
  3540.     }   }   }
  3541.  
  3542.     // head collision detection
  3543.     wormcol(player, worm[player].x, worm[player].y);
  3544.     // draw head
  3545.     field[worm[player].x][worm[player].y] = FIRSTHEAD + player;
  3546.     drawhead(player, worm[player].x, worm[player].y);
  3547.  
  3548.     updatearrow(worm[player].arrowy);
  3549.     worm[player].arrowy = worm[player].y;
  3550.     updatearrow(worm[player].arrowy);
  3551.  
  3552.     // protector collision detection
  3553.     for (thisprot = 0; thisprot <= PROTECTORS; thisprot++)
  3554.     {   if (protector[player][thisprot].alive && protector[player][thisprot].visible)
  3555.         {   protcol(player, protector[player][thisprot].x, protector[player][thisprot].y, thisprot);
  3556.             // draw protector
  3557.             if (protector[player][thisprot].alive && protector[player][thisprot].visible) // in case protector has just been killed, etc.
  3558.             {   change(protector[player][thisprot].x, protector[player][thisprot].y, FIRSTPROTECTOR + player);
  3559.     }   }   }
  3560.  
  3561.     if (worm[player].cutter)
  3562.     {   // straight ahead
  3563.         x = xwrap(worm[player].x + worm[player].deltax);
  3564.         y = ywrap(worm[player].y + worm[player].deltay);
  3565.         squareblast(HEAD, player, field[x][y], x, y, TRUE);
  3566.         // left
  3567.         if (!worm[player].deltax || !worm[player].deltay)
  3568.         {   // if orthagonal
  3569.             x = xwrap(worm[player].x + worm[player].deltay);
  3570.             y = ywrap(worm[player].y - worm[player].deltax);
  3571.         } else // diagonal
  3572.         {   if (worm[player].deltax == worm[player].deltay)
  3573.             {   x = xwrap(worm[player].x + worm[player].deltax);
  3574.                 y = ywrap(worm[player].y - worm[player].deltay);
  3575.             } else
  3576.             {   x = xwrap(worm[player].x - worm[player].deltax);
  3577.                 y = ywrap(worm[player].y + worm[player].deltay);
  3578.         }   }
  3579.         squareblast(HEAD, player, field[x][y], x, y, TRUE);
  3580.         // right
  3581.         if (!worm[player].deltax || !worm[player].deltay)
  3582.         {   // if orthagonal
  3583.             x = xwrap(worm[player].x - worm[player].deltay);
  3584.             y = ywrap(worm[player].y + worm[player].deltax);
  3585.         } else // diagonal
  3586.         {   if (worm[player].deltax == worm[player].deltay)
  3587.             {   x = xwrap(worm[player].x - worm[player].deltax);
  3588.                 y = ywrap(worm[player].y + worm[player].deltay);
  3589.             } else
  3590.             {   x = xwrap(worm[player].x + worm[player].deltax);
  3591.                 y = ywrap(worm[player].y - worm[player].deltay);
  3592.         }   }
  3593.         squareblast(HEAD, player, field[x][y], x, y, TRUE);
  3594.         // ahead left
  3595.         if (!worm[player].deltax || !worm[player].deltay)
  3596.         {   // if orthagonal
  3597.             if (worm[player].deltax) // if east or west
  3598.             {   x = xwrap(worm[player].x + worm[player].deltax);
  3599.                 y = ywrap(worm[player].y - worm[player].deltax);
  3600.             } else // north or south
  3601.             {   x = xwrap(worm[player].x + worm[player].deltay);
  3602.                 y = ywrap(worm[player].y + worm[player].deltay);
  3603.         }   }
  3604.         else // diagonal
  3605.         {   if (worm[player].deltax == worm[player].deltay)
  3606.             {   x = xwrap(worm[player].x + worm[player].deltax);
  3607.                 y = worm[player].y;
  3608.             } else
  3609.             {   x = worm[player].x;
  3610.                 y = ywrap(worm[player].y + worm[player].deltay);
  3611.         }   }
  3612.         squareblast(HEAD, player, field[x][y], x, y, TRUE);
  3613.         // ahead right
  3614.         if (!worm[player].deltax || !worm[player].deltay)
  3615.         {   // if orthagonal
  3616.             if (worm[player].deltax) // if east or west
  3617.             {   x = xwrap(worm[player].x + worm[player].deltax);;
  3618.                 y = ywrap(worm[player].y + worm[player].deltax);
  3619.             } else // north or south
  3620.             {   x = xwrap(worm[player].x - worm[player].deltay);
  3621.                 y = ywrap(worm[player].y + worm[player].deltay);
  3622.         }   }
  3623.         else // diagonal
  3624.         {   if (worm[player].deltax == worm[player].deltay)
  3625.             {   x = worm[player].x;
  3626.                 y = ywrap(worm[player].y + worm[player].deltay);
  3627.             } else
  3628.             {   x = xwrap(worm[player].x + worm[player].deltax);
  3629.                 y = worm[player].y;
  3630.         }   }
  3631.         squareblast(HEAD, player, field[x][y], x, y, TRUE);
  3632. }   }
  3633.  
  3634. MODULE void protcol(SBYTE player, SBYTE x, SBYTE y, SBYTE thisprot)
  3635. {   UBYTE c = field[x][y];
  3636.     SBYTE i;
  3637.  
  3638.     if (c >= FIRSTHEAD && c <= LASTHEAD)
  3639.     {   protworm(x, y, player, c - FIRSTHEAD);
  3640.     } elif (c >= FIRSTPROTECTOR && c <= LASTPROTECTOR)
  3641.     {   protprot(x, y, player, c - FIRSTPROTECTOR);
  3642.     } elif (c >= FIRSTTAIL && c <= LASTTAIL)
  3643.     {   if (player == c - FIRSTTAIL)
  3644.         {   protector[player][thisprot].visible = FALSE;
  3645.     }   }
  3646.     elif
  3647.     (   c == STONE
  3648.      || c == WOOD
  3649.      || c == METAL
  3650.      || c == TIMEBOMB
  3651.      || c == TELEPORT
  3652.      || c == FIRSTGLOW + player
  3653.     )
  3654.     {   protector[player][thisprot].visible = FALSE;
  3655.     } elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
  3656.     {   i = whichcreature(x, y, MISSILE, 255);
  3657.         protcreature(player, i);
  3658.     } elif (c >= FIRSTDRIP && c <= LASTDRIP)
  3659.     {   i = whichcreature(x, y, DRIP, 255);
  3660.         protcreature(player, i);
  3661.     } elif
  3662.     (   c == BIRD
  3663.      || c == CLOUD
  3664.      || c == DOG
  3665.      || c == FRAGMENT
  3666.      || c == ORB
  3667.      || c == PENGUIN
  3668.      || c == WHIRLWIND
  3669.     )
  3670.     {   i = whichcreature(x, y, c, 255);
  3671.         protcreature(player, i);
  3672.     } else
  3673.     {   bothcol(player, x, y);
  3674. }   }
  3675.  
  3676. MODULE void bothcol(SBYTE player, SBYTE x, SBYTE y)
  3677. {   UBYTE c = field[x][y];
  3678.  
  3679.     if (c >= FIRSTLETTER && c <= LASTLETTER)
  3680.     {   if (!(getnumber(player)))
  3681.         {   putnumber();
  3682.     }   }
  3683.     elif (c <= LASTOBJECT)
  3684.     {   wormscore(player, wormobject(player, x, y));
  3685.     } elif (c >= FIRSTGRAVE && c <= LASTGRAVE)
  3686.     {   effect(FXGET_SKULL);
  3687.         wormscore(player, POINTS_GRAVE);
  3688.         worm[player].bias += worm[c - FIRSTGRAVE].bias;
  3689.  
  3690.                 if (worm[player].bias > 0)
  3691.                 {   if (worm[player].bias > BIASLIMIT)
  3692.                         worm[player].bias = BIASLIMIT;
  3693.                     stat(player, BIAS);
  3694.                     worm[c - FIRSTGRAVE].bias = 0;
  3695.                     stat(c - FIRSTGRAVE, BIAS);
  3696.                 }
  3697.                 worm[player].multi *= worm[c - FIRSTGRAVE].multi;
  3698.                 if (worm[player].multi > 1)
  3699.                 {   if (worm[player].multi > MULTILIMIT)
  3700.                         worm[player].multi = MULTILIMIT;
  3701.                 }
  3702.                 worm[player].power += worm[c - FIRSTGRAVE].power;
  3703.                 if (worm[player].power > 1)
  3704.                 {   if (worm[player].power > POWERLIMIT)
  3705.                         worm[player].power = POWERLIMIT;
  3706.                     stat(player, POWER);
  3707.                     worm[c - FIRSTGRAVE].power = 0;
  3708.                     stat(c - FIRSTGRAVE, POWER);
  3709.                 }
  3710.                 worm[player].ammo += worm[c - FIRSTGRAVE].ammo;
  3711.                 if (worm[player].ammo > 0)
  3712.                 {   if (worm[player].ammo > AMMOLIMIT)
  3713.                         worm[player].ammo = AMMOLIMIT;
  3714.                     stat(player, AMMO);
  3715.                     worm[c - FIRSTGRAVE].ammo = 0;
  3716.                     stat(c - FIRSTGRAVE, AMMO);
  3717.                 }
  3718.                 worm[player].armour += worm[c - FIRSTGRAVE].armour;
  3719.                 if (worm[player].armour > 0)
  3720.                 {   if (worm[player].armour > ARMOURLIMIT)
  3721.                         worm[player].armour = ARMOURLIMIT;
  3722.                     stat(player, ARMOUR);
  3723.                     worm[c - FIRSTGRAVE].armour = 0;
  3724.                     stat(c - FIRSTGRAVE, ARMOUR);
  3725.                 }
  3726.                 if (worm[c - FIRSTGRAVE].brakes)
  3727.                 {   worm[player].brakes = TRUE;
  3728.                     stat(player, BRAKES);
  3729.                     worm[c - FIRSTGRAVE].brakes = FALSE;
  3730.                     worm[c - FIRSTGRAVE].speed = NORMAL;
  3731.                     stat(c - FIRSTGRAVE, BRAKES);
  3732.                 }
  3733.                 if (worm[c - FIRSTGRAVE].affixer)
  3734.                 {   worm[player].affixer = TRUE;
  3735.                     icon(player, AFFIXER);
  3736.                     worm[c - FIRSTGRAVE].affixer = FALSE;
  3737.                     icon(c - FIRSTGRAVE, AFFIXER);
  3738.                 }
  3739.                 if (worm[c - FIRSTGRAVE].remnants)
  3740.                 {   worm[player].remnants = TRUE;
  3741.                     icon(player, REMNANTS);
  3742.                     worm[c - FIRSTGRAVE].remnants = FALSE;
  3743.                     icon(c - FIRSTGRAVE, REMNANTS);
  3744.                 }
  3745.                 if (worm[c - FIRSTGRAVE].sideshot)
  3746.                 {   worm[player].sideshot = TRUE;
  3747.                     icon(player, SIDESHOT);
  3748.                     worm[c - FIRSTGRAVE].sideshot = FALSE;
  3749.                     icon(c - FIRSTGRAVE, SIDESHOT);
  3750.                 }
  3751.                 if (worm[c - FIRSTGRAVE].pusher)
  3752.                 {   worm[player].pusher = TRUE;
  3753.                     icon(player, PUSHER);
  3754.                     worm[c - FIRSTGRAVE].pusher = FALSE;
  3755.                     icon(c - FIRSTGRAVE, PUSHER);
  3756.                 }
  3757.                 if (worm[c - FIRSTGRAVE].encloser)
  3758.                 {   worm[player].encloser = TRUE;
  3759.                     icon(player, ENCLOSER);
  3760.                     worm[c - FIRSTGRAVE].encloser = FALSE;
  3761.                     icon(c - FIRSTGRAVE, ENCLOSER);
  3762.                 }
  3763.                 if (worm[c - FIRSTGRAVE].cutter)
  3764.                 {   worm[player].cutter += worm[c - FIRSTGRAVE].cutter;
  3765.                     icon(player, CUTTER);
  3766.                     worm[c - FIRSTGRAVE].cutter = 0;
  3767.                     icon(c - FIRSTGRAVE, CUTTER);
  3768.                 }
  3769.  
  3770.     } else
  3771.     {   switch(c)
  3772.         {
  3773.         case EMPTY:
  3774.             wormscore(player, POINTS_EMPTY);
  3775.         break;
  3776.         case SILVER:
  3777.             wormscore(player, POINTS_SILVER);
  3778.         break;
  3779.         case GOLD:
  3780.             wormscore(player, POINTS_GOLD);
  3781.         break;
  3782.         case DYNAMITE:
  3783.             effect(FXUSE_BOMB);
  3784.             banging = TRUE;
  3785.             bangdynamite(x, y, player);
  3786.             wormscore(player, worm[player].dynamitescore);
  3787.             worm[player].dynamitescore = 0;
  3788.         break;
  3789.         default:
  3790.         break;
  3791. }   }   } 
  3792.  
  3793. AGLOBAL void wormscore(SBYTE player, ULONG score)
  3794. {   worm[player].score += score * worm[player].multi * players;
  3795.     stat(player, BONUS);
  3796. }
  3797.  
  3798. SBYTE xwrap(SBYTE x)
  3799. {    if (x < 0)
  3800.         x += FIELDX + 1;
  3801.     elif (x > FIELDX)
  3802.         x -= FIELDX + 1;
  3803.     return(x);
  3804. }
  3805. SBYTE ywrap(SBYTE y)
  3806. {    if (y < 0)
  3807.         y += FIELDY + 1;
  3808.     elif (y > FIELDY)
  3809.         y -= FIELDY + 1;
  3810.     return(y);
  3811. }
  3812.  
  3813. MODULE void ramming(SBYTE player)
  3814. {   SBYTE i;
  3815.  
  3816.     worm[player].rammed = TRUE;
  3817.     worm[player].x = xwrap(worm[player].x - worm[player].deltax);
  3818.     worm[player].y = ywrap(worm[player].y - worm[player].deltay);
  3819.     for (i = 0; i <= PROTECTORS; i++)
  3820.     {   /* no point checking whether the protectors are alive or dead */
  3821.         protector[player][i].x -= worm[player].deltax;
  3822.         protector[player][i].y -= worm[player].deltay;
  3823. }   }
  3824.  
  3825. MODULE SWORD atleast(SWORD value, SWORD minimum)
  3826. {   if (value < minimum)
  3827.         return(minimum);
  3828.     else return(value);
  3829. }
  3830.  
  3831. MODULE void __inline change(SBYTE x, SBYTE y, UBYTE image)
  3832. {   // assert(valid(x, y));
  3833.     field[x][y] = image;
  3834.     draw(x, y, image);
  3835. }
  3836.  
  3837. /* WormWars FSET format for fieldset contents and high score table (Amiga
  3838. and IBM-PC), as follows:
  3839.  
  3840. header
  3841.         TEXT[]                          "FSET x.x" (NULL-terminated)
  3842.     SBYTE                levels;
  3843. high score table
  3844.     for (slot = 0; slot <= HISCORES; slot++)
  3845.     {    SBYTE            hiscore[slot].player,
  3846.                     hiscore[slot].level;
  3847.         SLONG            hiscore[slot].score;
  3848.         TEXT[]            hiscore[slot].name (NULL-terminated)
  3849.         TEXT[]            hiscore[slot].time (NULL-terminated)
  3850.         TEXT[]            hiscore[slot].date (NULL-terminated)
  3851.     }
  3852. level data
  3853.     for (level = 0; level <= levels; level++)
  3854.     {    SBYTE            startx[level],
  3855.                                         starty[level];
  3856.         ABOOL            teleport[level][0].alive;
  3857.         SBYTE            teleport[level][0].x,
  3858.                                         teleport[level][0].y;
  3859.         ABOOL            teleport[level][1].alive;
  3860.         SBYTE            teleport[level][1].x,
  3861.                                         teleport[level][1].y;
  3862.         for (x = 0; x <= FIELDX; x++)
  3863.             for (y = 0; y <= FIELDY; y++)
  3864.                 SBYTE    board[level][x][y];
  3865.     }
  3866. version string
  3867.         TEXT[]                          "$VER: Worm Wars x.x (dd.mm.yy) $" (NULL-terminated) */
  3868.  
  3869. MODULE SBYTE onlyworm(ABOOL alive)
  3870. {   SBYTE i,
  3871.           theworm = -1, // to prevent spurious warnings
  3872.           worms   = 0;
  3873.  
  3874.     for (i = 0; i <= 3; i++)
  3875.         if (worm[i].control != NONE && ((!alive) || worm[i].lives))
  3876.         {   theworm = i;
  3877.             worms++;
  3878.         }
  3879.     if (worms == 1)
  3880.         return (SBYTE) theworm;
  3881.     else return -1;
  3882. }
  3883.  
  3884. MODULE void wormkillcreature(UBYTE player, UBYTE which)
  3885. {   /* This is defensive programming. Sometimes squareblast() finds an
  3886.        orb on the field for which there is no corresponding creature
  3887.        (ie. an 'orphan orb'. whichcreature() on such a square will
  3888.        return 255. */
  3889.  
  3890.     if (which != 255)
  3891.     {   wormscore(player, creature[which].score);
  3892.         creature[which].alive = FALSE;
  3893.         if (worm[player].bias)
  3894.         {   worm[player].lives++;
  3895.             stat(player, LIFE);
  3896.         }
  3897.         if (creature[which].species == FRAGMENT)
  3898.         {   effect(FXDEATH_FRAGMENT);
  3899.         } elif (creature[which].species == DRIP)
  3900.         {   effect(FXGET_DRIP);
  3901. }   }   }
  3902.  
  3903. MODULE void wormworm(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3904. {   if (worm[which1].armour == 0 && worm[which2].armour == 0)
  3905.     {   /* both worms die */
  3906.         worm[which1].cause  = FIRSTHEAD + which2;
  3907.         worm[which1].alive  = FALSE;
  3908.         worm[which1].victor = -1;
  3909.         worm[which2].cause  = FIRSTHEAD + which1;
  3910.         worm[which2].alive  = FALSE;
  3911.         worm[which2].victor = -1;
  3912.     } elif (worm[which1].armour > 0 && worm[which2].armour == 0)
  3913.     {   /* 1st worm lives, 2nd worm dies  */
  3914.         worm[which2].cause  = FIRSTHEAD + which1;
  3915.         worm[which2].alive  = FALSE;
  3916.         worm[which2].victor = which1;
  3917.     } elif (worm[which1].armour == 0 && worm[which2].armour > 0)
  3918.     {   /* 1st worm dies, 2nd worm lives */
  3919.         worm[which1].cause  = FIRSTHEAD + which2;
  3920.         worm[which1].alive  = FALSE;
  3921.         worm[which1].victor = which2;
  3922. }   }
  3923. MODULE void protworm(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3924. {   SBYTE i, j = -1; // to prevent spurious warnings
  3925.  
  3926.     for (i = 0; i <= PROTECTORS; i++)
  3927.          if (protector[which1][i].alive && protector[which1][i].x == x && protector[which1][i].y == y)
  3928.          {    j = i;
  3929.               break;
  3930.          }
  3931.  
  3932.     if (which1 != which2)
  3933.     {   if (worm[which2].armour == 0)
  3934.         {   effect(FXUSE_PROTECTOR);
  3935.             worm[which2].cause  = FIRSTPROTECTOR + which1;
  3936.             worm[which2].victor = which1;
  3937.             worm[which2].alive  = FALSE;
  3938.         } else
  3939.         {   effect(FXUSE_ARMOUR);
  3940.             protector[which1][j].visible = FALSE;
  3941.     }   }
  3942.     else
  3943.     {   /* protector is over worm's own head; caused by ramming */
  3944.         protector[which1][j].visible = FALSE;
  3945. }   }
  3946. MODULE void protprot(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3947. {   SBYTE i, p1 = -1, p2 = -1; // to prevent spurious warnings
  3948.  
  3949.     /* Find both protectors */
  3950.  
  3951.     for (i = 0; i <= PROTECTORS; i++)
  3952.     {   if (protector[which1][i].alive && protector[which1][i].x == x && protector[which1][i].y == y)
  3953.             p1 = i;
  3954.         if (protector[which2][i].alive && protector[which2][i].x == x && protector[which2][i].y == y)
  3955.             p2 = i;
  3956.     }
  3957.     protector[which1][p1].alive = FALSE;
  3958.     protector[which2][p2].alive = FALSE;
  3959.     change(x, y, EMPTY);
  3960. }
  3961.  
  3962. MODULE ULONG wormobject(UBYTE player, SBYTE x, SBYTE y)
  3963. {   AUTO    UBYTE c = field[x][y], d;
  3964.     AUTO    ULONG score = object[c].score;
  3965.     AUTO    UBYTE i, j, generated = 0;
  3966.     AUTO    SBYTE xx, xxx, yy, yyy;
  3967.     AUTO    ABOOL done;
  3968.     PERSIST UBYTE otherfield[FIELDX + 1][FIELDY + 1];
  3969.  
  3970.     for (i = 0; i <= MAGNETS; i++)
  3971.         if (magnet[i].alive && x == magnet[i].x && y == magnet[i].y)
  3972.              magnet[i].alive = FALSE;
  3973.  
  3974.     if (!valid(x, y)) // defensive programming
  3975.     {   return 0;
  3976.  
  3977.         /* AUTO TEXT temp1[SAYLIMIT + 1], temp2[8];
  3978.  
  3979.         strcpy(temp1, "BAD OBJECT AT x: ");
  3980.         stci_d(temp2, x);
  3981.         strcat(temp1, temp2);
  3982.         strcat(temp1, ", y: ");
  3983.         stci_d(temp2, y);
  3984.         strcat(temp1, temp2);
  3985.         strcat(temp1, "!");
  3986.         say(temp1, worm[player].colour);
  3987.         draw(FIELDX + 1, 0, c); // indicates which object
  3988.         Delay(250);
  3989.         clearkybd();
  3990.         anykey(FALSE); */
  3991.     }
  3992.  
  3993.     switch(c)
  3994.     {
  3995.     case BONUS:
  3996.         getnumber(player);
  3997.         change(numberx, numbery, FIRSTLETTER + number - 1);
  3998.         updatearrow(numbery);
  3999.     break;
  4000.     case AMMO:
  4001.         effect(FXGET_AMMO);
  4002.         worm[player].ammo += arand(4) + 2; /* 2-6 bullets */
  4003.         stat(player, AMMO);
  4004.     break;
  4005.     case ARMOUR:
  4006.         effect(FXGET_OBJECT);
  4007.         worm[player].armour += ADD_ARMOUR + arand(RAND_ARMOUR);
  4008.         stat(player, ARMOUR);
  4009.     break;
  4010.     case BRAKES:
  4011.         effect(FXGET_OBJECT);
  4012.         worm[player].brakes = TRUE;
  4013.         stat(player, BRAKES);
  4014.     break;
  4015.     case BOMB:
  4016.         if (worm[player].glow == 0)
  4017.             draw(worm[player].x, worm[player].y, eachworm[player][0][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  4018.         else draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  4019.         bombblast(HEAD, player, worm[player].x, worm[player].y);
  4020.     break;
  4021.     case POWER:
  4022.         effect(FXGET_POWERUP);
  4023.         if (worm[player].power < POWERLIMIT)
  4024.         {   worm[player].power += 2;
  4025.             stat(player, POWER);
  4026.         }
  4027.     break;
  4028.     case SLAYER:
  4029.         for (i = 0; i <= CREATURES; i++)
  4030.         {   if (creature[i].alive)
  4031.             {   if
  4032.                 (   (   creature[i].species != MISSILE
  4033.                      && creature[i].species != DRIP
  4034.                     )
  4035.                  || creature[i].type != player
  4036.                 )
  4037.                 {   wormkillcreature(player, i);
  4038.                     change(creature[i].x, creature[i].y, EMPTY);
  4039.         }   }   }
  4040.         for (i = 0; i <= 3; i++)
  4041.         {   if (player != i && worm[i].armour == 0)
  4042.             {   worm[i].alive = FALSE;
  4043.                 worm[i].cause = SLAYER;
  4044.                 worm[i].victor = player;
  4045.         }   }
  4046.         for (x = 0; x <= FIELDX; x++)
  4047.             for (y = 0; y <= FIELDY; y++)
  4048.                 if (field[x][y] == SLIME)
  4049.                     change(x, y, EMPTY);
  4050.     break;
  4051.     case PROTECTOR:
  4052.         // create protector
  4053.         done = FALSE;
  4054.         for (i = 0; i <= PROTECTORS; i++)
  4055.         {   if (!protector[player][i].alive && !done)
  4056.             {   do
  4057.                 {   protector[player][i].relx = (arand(1) * 2) - 1;
  4058.                     protector[player][i].rely = (arand(1) * 2) - 1;
  4059.                     for (j = 0; j <= PROTECTORS; j++)
  4060.                     {   if
  4061.                         (   i == NOSE
  4062.                          || !protector[player][j].alive
  4063.                          ||  protector[player][j].x != xwrap(worm[player].x + protector[player][i].relx)
  4064.                          ||  protector[player][j].y != ywrap(worm[player].y + protector[player][i].rely)
  4065.                         ) // if we can find an area without a preexisting protector
  4066.                         {   effect(FXBORN_PROTECTOR);
  4067.                             done = TRUE;
  4068.                             protector[player][i].alive = TRUE;
  4069.                             protector[player][i].visible = FALSE;
  4070.                             protector[player][i].last = EMPTY;
  4071.                             if (i == NOSE)
  4072.                             {   worm[player].position = -1;
  4073.                 }   }   }   }
  4074.                 while (!done);
  4075.         }   }
  4076.     break;
  4077.     case MISSILE:
  4078.         for (i = 0; i <= CREATURES; i++)
  4079.         {   if (!creature[i].alive)
  4080.             {   createcreature(MISSILE, i, worm[player].x, worm[player].y, 0, 0, player);
  4081.                 break;
  4082.         }   }
  4083.     break;
  4084.     case LIFE:
  4085.         effect(FXGET_OBJECT);
  4086.         worm[player].lives += arand(4) + 2; /* 2-6 lives */
  4087.         stat(player, LIFE);
  4088.     break;
  4089.     case MULTIPLIER:
  4090.         effect(FXGET_OBJECT);
  4091.         if (worm[player].multi < MULTILIMIT)
  4092.             worm[player].multi *= 2;
  4093.     break;
  4094.     case BIAS:
  4095.         effect(FXGET_OBJECT);
  4096.         worm[player].bias += ADD_ARMOUR + arand(RAND_ARMOUR);
  4097.         stat(player, BIAS);
  4098.     break;
  4099.     case ICE:
  4100.         effect(FXGET_OBJECT);
  4101.         ice += ADD_ICE + arand(RAND_ICE);
  4102.     break;
  4103.     case GROWER:
  4104.         effect(FXGET_GROWER);
  4105.  
  4106.         /* grow dynamite */
  4107.         for (x = 0; x <= FIELDX; x++)
  4108.             for (y = 0; y <= FIELDY; y++)
  4109.                 if (field[x][y] == DYNAMITE)
  4110.                     for (xx = x - 1; xx <= x + 1; xx++)
  4111.                         for (yy = y - 1; yy <= y + 1; yy++)
  4112.                             if (valid(xx, yy))
  4113.                                 if (field[xx][yy] == EMPTY)
  4114.                                     field[xx][yy] = TEMPDYNAMITE;
  4115.         /* grow silver */
  4116.         for (x = 0; x <= FIELDX; x++)
  4117.             for (y = 0; y <= FIELDY; y++)
  4118.                 if (field[x][y] == SILVER)
  4119.                     for (xx = x - 1; xx <= x + 1; xx++)
  4120.                         for (yy = y - 1; yy <= y + 1; yy++)
  4121.                             if (valid(xx, yy))
  4122.                                 if (field[xx][yy] == EMPTY || field[xx][yy] == TEMPDYNAMITE)
  4123.                                     field[xx][yy] = TEMPSILVER;
  4124.         /* grow gold */
  4125.         for (x = 0; x <= FIELDX; x++)
  4126.             for (y = 0; y <= FIELDY; y++)
  4127.                 if (field[x][y] == GOLD)
  4128.                     for (xx = x - 1; xx <= x + 1; xx++)
  4129.                         for (yy = y - 1; yy <= y + 1; yy++)
  4130.                             if (valid(xx, yy))
  4131.                                 if (field[xx][yy] == EMPTY || field[xx][yy] == TEMPDYNAMITE || field[xx][yy] == TEMPSILVER)
  4132.                                     field[xx][yy] = TEMPGOLD;
  4133.         /* update field */
  4134.         for (x = 0; x <= FIELDX; x++)
  4135.             for (y = 0; y <= FIELDY; y++)
  4136.                 switch (field[x][y])
  4137.                 {
  4138.                 case TEMPGOLD:
  4139.                     change(x, y, GOLD);
  4140.                 break;
  4141.                 case TEMPSILVER:
  4142.                     change(x, y, SILVER);
  4143.                 break;
  4144.                 case TEMPDYNAMITE:
  4145.                     change(x, y, DYNAMITE);
  4146.                 break;
  4147.                 default:
  4148.                 break;
  4149.                 }
  4150.     break;
  4151.     case TREASURE:
  4152.         treasurer = player;
  4153.         if (level)
  4154.         {   secondsperlevel = 0;
  4155.             leveltype = arand(2);
  4156.             if (leveltype == 0)
  4157.             {   say("Bonus Level: Treasury!", worm[treasurer].colour);
  4158.                 leveltype = TREASURE;
  4159.             } elif (leveltype == 1)
  4160.             {   say("Bonus Level: Drips!", worm[treasurer].colour);
  4161.                 leveltype = DRIP;
  4162.             } else
  4163.             {   // assert(leveltype == 2);
  4164.                 say("Bonus Level: Penguins!", worm[treasurer].colour);
  4165.                 leveltype = PENGUIN;
  4166.         }   }
  4167.         secondsperlevel += ADD_TREASURE + arand(RAND_TREASURE);
  4168.         if (level && leveltype != TREASURE)
  4169.             secondsperlevel *= 2;
  4170.         if (secondsperlevel > TIMELIMIT)
  4171.             secondsperlevel = TIMELIMIT;
  4172.         if (level)
  4173.         {   stat(player, BONUS);
  4174.             reallevel = level;
  4175.             level = 0;
  4176.             newlevel(player);
  4177.         }
  4178.     break;
  4179.     case AFFIXER:
  4180.         effect(FXGET_OBJECT);
  4181.         worm[player].affixer = TRUE;
  4182.         icon(player, AFFIXER);
  4183.     break;
  4184.     case SWITCHER:
  4185.         effect(FXGET_OBJECT);
  4186.         for (x = 0; x <= FIELDX; x++)
  4187.         {   for (y = 0; y <= FIELDY; y++)
  4188.             {   if (field[x][y] >= FIRSTTAIL && field[x][y] <= LASTTAIL)
  4189.                 {   if (field[x][y] == FIRSTTAIL + player)
  4190.                     {   change(x, y, FIRSTGLOW + player);
  4191.                     } else
  4192.                     {   change(x, y, FIRSTTAIL + player);
  4193.                 }   }
  4194.                 elif (worm[player].bias)
  4195.                 {   if (field[x][y] >= FIRSTGLOW && field[x][y] <= LASTGLOW && field[x][y] != FIRSTGLOW + player)
  4196.                         change(x, y, FIRSTGLOW + player);
  4197.                     elif (field[x][y] == SLIME)
  4198.                         change(x, y, DYNAMITE);
  4199.         }   }   }
  4200.     break;
  4201.     case HEALER:
  4202.         effect(FXGET_OBJECT);
  4203.         if (worm[player].lives < 100)
  4204.             worm[player].lives = 100;
  4205.         else worm[player].lives = LIVESLIMIT;
  4206.         stat(player, LIFE);
  4207.     break;
  4208.     case UMBRELLA:
  4209.         level += arand(1) + 1;
  4210.         if (level >= levels)
  4211.             level = levels; // fixed?
  4212.         endoflevel();
  4213.     break;
  4214.     case CLOCK:
  4215.         effect(FXGET_OBJECT);
  4216.         secondsperlevel += ADD_CLOCK + arand(RAND_CLOCK);
  4217.         if (secondsperlevel > TIMELIMIT)
  4218.         {   secondsperlevel = TIMELIMIT;
  4219.         }
  4220.     break;
  4221.     case SLOWER:
  4222.         effect(FXGET_OBJECT);
  4223.         for (i = 0; i <= CREATURES; i++)
  4224.             if (creature[i].alive && creature[i].species != MISSILE)
  4225.                 creature[i].speed = (SBYTE) atleast(creature[i].speed * 2, VERYFAST);
  4226.     break;
  4227.     case PULSE:
  4228.         effect(FXGET_PULSE);
  4229.         for (i = 0; i <= CREATURES; i++)
  4230.         {   if (!creature[i].alive && generated <= 7)
  4231.             {   switch (generated)
  4232.                 {
  4233.                 case 0:
  4234.                     xx = 0;
  4235.                     yy = -1;
  4236.                 break;
  4237.                 case 1:
  4238.                     xx = 1;
  4239.                     yy = -1;
  4240.                 break;
  4241.                 case 2:
  4242.                     xx = 1;
  4243.                     yy = 0;
  4244.                 break;
  4245.                 case 3:
  4246.                     xx = 1;
  4247.                     yy = 1;
  4248.                 break;
  4249.                 case 4:
  4250.                     xx = 0;
  4251.                     yy = 1;
  4252.                 break;
  4253.                 case 5:
  4254.                     xx = -1;
  4255.                     yy = 1;
  4256.                 break;
  4257.                 case 6:
  4258.                     xx = -1;
  4259.                     yy = 0;
  4260.                 break;
  4261.                 case 7:
  4262.                     xx = -1;
  4263.                     yy = -1;
  4264.                 break;
  4265.                 default:
  4266.                 break;
  4267.                 }
  4268.  
  4269.                 generated++;
  4270.                 if (valid(x + xx, y + yy) && (xx != worm[player].deltax || yy != worm[player].deltay))
  4271.                 {   d = field[x + xx][y + yy];
  4272.                     if ((d >= FIRSTEMPTY && d <= LASTEMPTY) || (d >= FIRSTTAIL && d <= LASTTAIL) || d <= LASTOBJECT)
  4273.                     {   createcreature(FRAGMENT, i, x + xx, y + yy, xx, yy, 255);
  4274.         }   }   }   }
  4275.     break;
  4276.     case REMNANTS:
  4277.         effect(FXGET_OBJECT);
  4278.         worm[player].remnants = TRUE;
  4279.         icon(player, REMNANTS);
  4280.     break;
  4281.     case SIDESHOT:
  4282.         effect(FXGET_POWERUP);
  4283.         worm[player].sideshot = TRUE;
  4284.         icon(player, SIDESHOT);
  4285.     break;
  4286.     case MAGNET:
  4287.         effect(FXGET_OBJECT);
  4288.         i = 0;
  4289.         field[x][y] = EMPTY; // so that the magnet itself is destroyed
  4290.         for (xx = 0; xx <= FIELDX; xx++)
  4291.             for (yy = 0; yy <= FIELDY; yy++)
  4292.                 if (field[xx][yy] <= LASTOBJECT)
  4293.                 {   while (magnet[i].alive && i < MAGNETS)
  4294.                        i++;
  4295.                     if (i > MAGNETS)
  4296.                     {   break;
  4297.                     } else
  4298.                     {   magnet[i].x      = xx;
  4299.                         magnet[i].y      = yy;
  4300.                         magnet[i].object = field[xx][yy];
  4301.                         magnet[i].player = player;
  4302.                         magnet[i].alive  = TRUE;
  4303.                         i++;
  4304.                 }   }
  4305.     break;
  4306.     case CUTTER:
  4307.         effect(FXGET_OBJECT);
  4308.         worm[player].cutter += ADD_CUTTER + arand(RAND_CUTTER);
  4309.         icon(player, CUTTER);
  4310.     break;
  4311.     case CYCLONE:
  4312.         /* create whirlwind */
  4313.         do
  4314.         {   x = arand(FIELDX - 10) + 5;
  4315.             y = arand(FIELDY - 5) + 5;
  4316.             d = field[x][y];
  4317.         } while (d < FIRSTEMPTY || d > LASTEMPTY);
  4318.         for (i = 0; i <= CREATURES; i++)
  4319.         {   if (!creature[i].alive)
  4320.             {   createcreature(WHIRLWIND, i, x, y, 0, 0, 255);
  4321.                 break;
  4322.         }   }
  4323.     break;
  4324.     case LIGHTNING:
  4325.         effect(FXGET_OBJECT);
  4326.         for (xx = 0; xx <= FIELDX; xx++)
  4327.             for (yy = 0; yy <= FIELDY; yy++)
  4328.                 otherfield[xx][yy] = EMPTY;
  4329.         for (xx = 0; xx <= FIELDX; xx++)
  4330.             for (yy = 0; yy <= FIELDY; yy++)
  4331.                 if (field[xx][yy] == FIRSTTAIL + player)
  4332.                     for (xxx = xx - 1; xxx <= xx + 1; xxx++)
  4333.                         for (yyy = yy - 1; yyy <= yy + 1; yyy++)
  4334.                             if (valid(xxx, yyy))
  4335.                             {   d = field[xxx][yyy];
  4336.                                 if (d == ORB
  4337.                                  || d == GOAT
  4338.                                  || d == MISSILE
  4339.                                  || d == PENGUIN
  4340.                                  || d == FISH
  4341.                                  || d == FRAGMENT
  4342.                                  || (d >= FIRSTTAIL && d <= LASTTAIL && d != FIRSTTAIL + player)
  4343.                                  || (d >= FIRSTHEAD && d <= LASTHEAD)
  4344.                                  || (d >= FIRSTDRIP && d <= LASTDRIP)
  4345.                                  || d <= LASTOBJECT)
  4346.                                 {   otherfield[xxx][yyy] = TEMPLIGHTNING;
  4347.                                     draw(xxx, yyy, LIGHTNING);
  4348.                             }   }
  4349.         for (xx = 0; xx <= FIELDX; xx++)
  4350.         {   for (yy = 0; yy <= FIELDY; yy++)
  4351.             {   if (otherfield[xx][yy] == TEMPLIGHTNING)
  4352.                 {   d = field[xx][yy];
  4353.                     if (d >= FIRSTMISSILE && d <= LASTMISSILE)
  4354.                     {   i = whichcreature(xx, yy, MISSILE, 255);
  4355.                         if (player != creature[i].type)
  4356.                         {   wormkillcreature(player, i);
  4357.                             change(xx, yy, EMPTY);
  4358.                         } else drawmissile(xx, yy, i);
  4359.                     } elif (d >= FIRSTDRIP && d <= LASTDRIP)
  4360.                     {   i = whichcreature(xx, yy, DRIP, 255);
  4361.                         if (player != creature[i].type)
  4362.                         {   wormkillcreature(player, i);
  4363.                             change(xx, yy, EMPTY);
  4364.                         } else draw(xx, yy, FIRSTDRIP + player);
  4365.                     } else
  4366.                     {   switch(d)
  4367.                         {
  4368.                         case CLOUD:
  4369.                         case DOG:
  4370.                         case FRAGMENT:
  4371.                         case GIRAFFE:
  4372.                         case GOAT:
  4373.                         case LION:
  4374.                         case OCTOPUS:
  4375.                         case ORB:
  4376.                         case PENGUIN:
  4377.                         case WHIRLWIND:
  4378.                             wormkillcreature(player, whichcreature(xx, yy, d, 255));
  4379.                             change(xx, yy, EMPTY);
  4380.                         break;
  4381.                         default:
  4382.                             /* eg. tail */
  4383.                             change(xx, yy, EMPTY);
  4384.                         break;
  4385.         }   }   }   }   }
  4386.     break;
  4387.     case PUSHER:
  4388.         effect(FXGET_OBJECT);
  4389.         worm[player].pusher = TRUE;
  4390.         icon(player, PUSHER);
  4391.     break;
  4392.     case GLOW:
  4393.         effect(FXGET_OBJECT);
  4394.         worm[player].glow += ADD_GLOW + arand(RAND_GLOW);
  4395.         if (worm[player].glow > GLOWLIMIT)
  4396.             worm[player].glow = GLOWLIMIT;
  4397.                 icon(player, GLOW);
  4398.     break;
  4399.     case ENCLOSER:
  4400.         effect(FXGET_OBJECT);
  4401.         worm[player].encloser = TRUE;
  4402.         icon(player, ENCLOSER);
  4403.     break;
  4404.     case CONVERTER:
  4405.         effect(FXGET_OBJECT);
  4406.         for (i = 0; i <= CREATURES; i++)
  4407.             if (creature[i].alive && creature[i].species == FRAGMENT)
  4408.             {   xx = creature[i].x;
  4409.                 yy = creature[i].y;
  4410.                 creature[i].alive = FALSE;
  4411.                 change(xx, yy, EMPTY);
  4412.                 createcreature(MISSILE, i, xx, yy, 0, 0, player);
  4413.             }
  4414.     break;
  4415.     default:
  4416.         // assert(0);
  4417.     break;
  4418.     }
  4419.     return(score);
  4420. }
  4421.  
  4422. void icon(SBYTE player, UBYTE image)
  4423. {   /* Updates one of the boolean icons. The routine checks
  4424.     the status directly. */
  4425.  
  4426.     SBYTE x = -4, y = (player * 10) + 7;
  4427.  
  4428.     switch(image)
  4429.     {
  4430.     case AFFIXER:
  4431.         if (worm[player].affixer)
  4432.             draw(x, y, AFFIXER);
  4433.         else draw(x, y, BLACKENED);
  4434.     break;
  4435.     case PUSHER:
  4436.         if (worm[player].pusher)
  4437.             draw(x + 1, y, PUSHER);
  4438.         else draw(x + 1, y, BLACKENED);
  4439.     break;
  4440.     case REMNANTS:
  4441.         if (worm[player].remnants)
  4442.             draw(x + 2, y, REMNANTS);
  4443.         else draw(x + 2, y, BLACKENED);
  4444.     break;
  4445.     case SIDESHOT:
  4446.         if (worm[player].sideshot)
  4447.             draw(x, y + 1, SIDESHOT);
  4448.         else draw(x, y + 1, BLACKENED);
  4449.     break;
  4450.     case CUTTER:
  4451.         if (worm[player].cutter)
  4452.         {   if (worm[player].cutter < 10)
  4453.             {   if ((r % 4) <= 1)
  4454.                 {   draw(x + 1, y + 1, CUTTER);
  4455.                 } else draw(x + 1, y + 1, BLACKENED);
  4456.             } else draw(x + 1, y + 1, CUTTER);
  4457.         } else draw(x + 1, y + 1, BLACKENED);
  4458.     break;
  4459.     case ENCLOSER:
  4460.         if (worm[player].encloser)
  4461.             draw(x + 2, y + 1, ENCLOSER);
  4462.         else draw(x + 2, y + 1, BLACKENED);
  4463.     break;
  4464.     default:
  4465.     break;
  4466. }   }
  4467.  
  4468. MODULE void wormcol(SBYTE player, SBYTE x, SBYTE y)
  4469. {   ABOOL flag;
  4470.     UBYTE c = field[x][y], d;
  4471.     SBYTE i, xx, yy;
  4472.     ULONG score = 0;
  4473.  
  4474.     if (c >= FIRSTHEAD && c <= LASTHEAD)
  4475.         wormworm(x, y, player, c - FIRSTHEAD);
  4476.     elif (c == TIMEBOMB)
  4477.     {   /* push timebomb */
  4478.         i = whichcreature(x, y, TIMEBOMB, 255);
  4479.         if (valid(x + worm[player].deltax, y + worm[player].deltay))
  4480.         {   d = field[x + worm[player].deltax][y + worm[player].deltay];
  4481.             if (d <= LASTEMPTY)
  4482.             {   creature[i].x += worm[player].deltax;
  4483.                 creature[i].y += worm[player].deltay;
  4484.                 field[creature[i].x][creature[i].y] = TIMEBOMB;
  4485.                 draw(creature[i].x, creature[i].y, ZERO + creature[i].time);
  4486.             } else // oops, you've fucked up! :-( Timebomb explodes!
  4487.             {   if (worm[player].glow == 0)
  4488.                     draw(worm[player].x, worm[player].y, eachworm[player][0][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  4489.                 else draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  4490.                 bombblast(HEAD, player, worm[player].x, worm[player].y);
  4491.                 creature[i].alive = FALSE;
  4492.         }   }
  4493.         else
  4494.         {   score += creature[i].score;
  4495.     }   }
  4496.     elif (c == ARROWUP)
  4497.     {   if (worm[player].deltay == -1)
  4498.         {   worm[player].speed = speedup(worm[player].speed, worm[player].brakes);
  4499.         } elif (worm[player].deltay == 1)
  4500.         {   worm[player].speed = slowdown(worm[player].speed, worm[player].brakes);
  4501.         }
  4502.         worm[player].last = ARROWUP;
  4503.     } elif (c == ARROWDOWN)
  4504.     {   if (worm[player].deltay == 1)
  4505.         {   worm[player].speed = speedup(worm[player].speed, worm[player].brakes);
  4506.         } elif (worm[player].deltay == -1)
  4507.         {   worm[player].speed = slowdown(worm[player].speed, worm[player].brakes);
  4508.         }
  4509.         worm[player].last = ARROWDOWN;
  4510.     } elif (c == FROST)
  4511.     {   worm[player].frosted = TRUE;
  4512.     } elif (c >= FIRSTPROTECTOR && c <= LASTPROTECTOR)
  4513.     {   protworm(x, y, c - FIRSTPROTECTOR, player);
  4514.     } elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
  4515.     {   i = whichcreature(x, y, MISSILE, 255);
  4516.         wormcreature(player, i);
  4517.     } elif (c >= FIRSTDRIP && c <= LASTDRIP)
  4518.     {   i = whichcreature(x, y, DRIP, 255);
  4519.         wormcreature(player, i);
  4520.     } elif
  4521.     (   c == STONE
  4522.      || c == METAL
  4523.      || c == WOOD
  4524.      || c == FISH
  4525.      || c == GOAT
  4526.      || c == OCTOPUS
  4527.      || (c >= FIRSTTAIL && c <= LASTTAIL)
  4528.     ) // if you've hit something that is pushable
  4529.     {   flag = TRUE; // flag is whether you deserve to die
  4530.         if (worm[player].pusher)
  4531.         {   xx = x + worm[player].deltax;
  4532.             yy = y + worm[player].deltay;
  4533.             if (valid(xx, yy))
  4534.             {   d = field[xx][yy];
  4535.                 if (d <= LASTEMPTY)
  4536.                 // if you're pushing the square into a square which
  4537.                 // has an object or is empty/silver/gold
  4538.                 {   flag = FALSE; // then you don't deserve to die
  4539.                     if
  4540.                     (   c == FISH
  4541.                      || c == GOAT
  4542.                      || c == OCTOPUS
  4543.                     )
  4544.                     {   i = whichcreature(x, y, c, 255);
  4545.                         creature[i].x = xx;
  4546.                         creature[i].y = yy;
  4547.                         creature[i].visible = FALSE;
  4548.                     }
  4549.                     field[xx][yy] = c;
  4550.                     draw(xx, yy, c);
  4551.             }   }                 
  4552.             else // if pushing off the field edges
  4553.             {   flag = FALSE; // then you don't deserve to die
  4554.                 // kill the creature
  4555.                 if
  4556.                 (   c == FISH
  4557.                  || c == GOAT
  4558.                  || c == OCTOPUS
  4559.                 )
  4560.                 {   i = whichcreature(x, y, c, 255);
  4561.                     wormkillcreature(player, i);
  4562.         }   }   }
  4563.         if (flag) // if we deserve to die
  4564.         {   if (c >= FIRSTTAIL && c <= LASTTAIL) // if we're pushing/hitting tail
  4565.             {   if (worm[player].armour > 0)
  4566.                 {   effect(FXUSE_ARMOUR);
  4567.                     if (players > 1)
  4568.                     {   if (player == c - FIRSTTAIL)
  4569.                         {   score += POINTS_TURNSILVER;
  4570.                             worm[player].last = SILVER;
  4571.                         } else
  4572.                         {   score += POINTS_TURNGOLD;
  4573.                             worm[player].last = GOLD;
  4574.                 }   }   }
  4575.                 elif (!enclosed)
  4576.                 {   worm[player].cause = c;
  4577.                     worm[player].alive = FALSE;
  4578.                     worm[player].victor = c - FIRSTTAIL;
  4579.             }   }
  4580.             elif
  4581.             (   c == FISH
  4582.              || c == GOAT
  4583.              || c == OCTOPUS
  4584.             )
  4585.             {   i = whichcreature(x, y, c, 255);
  4586.                 wormcreature(player, i);
  4587.             } else
  4588.             {   worm[player].cause = c;
  4589.                 worm[player].alive = FALSE;
  4590.                 worm[player].victor = -1;
  4591.                 if (c != WOOD)
  4592.                 {   ramming(player);
  4593.     }   }   }   }
  4594.     elif (c == SLIME)
  4595.     {   if (worm[player].armour == 0)
  4596.         {   worm[player].cause = c;
  4597.             worm[player].alive = FALSE;
  4598.             worm[player].victor = -1;
  4599.     }   }
  4600.     elif
  4601.     (   c == BIRD
  4602.      || c == CLOUD
  4603.      || c == DOG
  4604.      || c == FRAGMENT
  4605.      || c == GIRAFFE
  4606.      || c == LION
  4607.      || c == ORB
  4608.      || c == PENGUIN
  4609.      || c == WHIRLWIND
  4610.     )
  4611.     {   i = whichcreature(x, y, c, 255);
  4612.         wormcreature(player, i);
  4613.     } elif (c == TELEPORT)
  4614.     {   i = whichteleport(x, y);
  4615.         if (blocked(i, worm[player].deltax, worm[player].deltay))
  4616.         {   worm[player].cause = TELEPORT;
  4617.             worm[player].victor = -1;
  4618.             worm[player].alive = FALSE;
  4619.             ramming(player);
  4620.         } else
  4621.         {   effect(FXUSE_TELEPORT);
  4622.             worm[player].x = xwrap(teleport[level][partner(i)].x + worm[player].deltax);
  4623.             worm[player].y = ywrap(teleport[level][partner(i)].y + worm[player].deltay);
  4624.     }   }
  4625.     elif (c >= FIRSTGLOW && c <= LASTGLOW)
  4626.     {   if (player != c - FIRSTGLOW)
  4627.         {   if (worm[player].armour == 0)
  4628.             {   worm[player].cause = GLOW;
  4629.                 worm[player].victor = c - FIRSTGLOW;
  4630.                 worm[player].alive = FALSE;
  4631.             }
  4632.             ramming(player);
  4633.     }   }
  4634.     else bothcol(player, x, y);
  4635.     wormscore(player, score);
  4636. }
  4637.  
  4638. AGLOBAL void drawhead(SBYTE player, SBYTE x, SBYTE y)
  4639. {   if (worm[player].alive)
  4640.     {   if (worm[player].glow == 0)
  4641.         {   draw(worm[player].x, worm[player].y, eachworm[player][0][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  4642.             worm[player].flashed = FALSE;
  4643.         } else
  4644.         {   if (worm[player].glow < 10)
  4645.             {   if (!worm[player].flashed)
  4646.                 {   draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  4647.                 } else draw(worm[player].x, worm[player].y, WHITENED);
  4648.                 worm[player].flashed = !worm[player].flashed;
  4649.             } else draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  4650.     }   }
  4651.     else draw(worm[player].x, worm[player].y, FIRSTPAIN + player);
  4652. }
  4653.  
  4654. AGLOBAL void drawsquare(SBYTE x, SBYTE y)
  4655. {   UBYTE which;
  4656.  
  4657.     if (field[x][y] == DOG)
  4658.     {   which = whichcreature(x, y, DOG, 255);
  4659.         if (!creature[which].dormant)
  4660.         {   draw(x, y, DOGDORMANT);
  4661.         } elif (creature[which].dormant <= CHASING)
  4662.         {   draw(x, y, DOGAWAKENING);
  4663.         } else
  4664.         {   draw(x, y, DOG);
  4665.     }   }
  4666.     elif (field[x][y] >= FIRSTHEAD && field[x][y] <= LASTHEAD)
  4667.     {   drawhead(field[x][y] - FIRSTHEAD, x, y);
  4668.     } else
  4669.     {   draw(x, y, field[x][y]);
  4670. }   }
  4671.  
  4672. MODULE void updatearrow(SBYTE arrowy)
  4673. {   SBYTE i, var = -1;
  4674.  
  4675.     /* var of:
  4676.                   -2         : many there
  4677.                   -1         : nothing there
  4678.                  0-3         : just that worm,
  4679.        FIRSTLETTER-LASTLETTER: just that number */
  4680.  
  4681.     for (i = 0; i <= 3; i++)
  4682.     {   if
  4683.         (   worm[i].control != NONE
  4684.          && worm[i].y == arrowy
  4685.          && (   worm[i].lives
  4686.              || (   field[worm[i].x][worm[i].y] >= FIRSTGRAVE
  4687.                  && field[worm[i].x][worm[i].y] <= LASTGRAVE
  4688.         )   )   )
  4689.         {   if (var == -1)
  4690.                 var = i;
  4691.             else var = -2;
  4692.     }   }
  4693.     if (numbery == arrowy)
  4694.         if (var == -1)
  4695.             var = FIRSTLETTER + number - 1;
  4696.         else var = -2;
  4697.     if (var == -2)
  4698.         draw(ARROWX, arrowy, ALL);
  4699.     elif (var == -1)
  4700.         draw(ARROWX, arrowy, BLACKARROW);
  4701.     elif (var >= FIRSTLETTER && var <= LASTLETTER)
  4702.         draw(ARROWX, arrowy, var);
  4703.     else
  4704.     {   // assert(var >= 0 && var <= 3);
  4705.         if (worm[var].lives)
  4706.             draw(ARROWX, arrowy, FIRSTARROW + var);
  4707.         else draw(ARROWX, arrowy, FIRSTGRAVE + var);
  4708. }   }
  4709.  
  4710. MODULE void __inline bangdynamite(SBYTE x, SBYTE y, SBYTE player)
  4711. {   SBYTE xx, yy;
  4712.  
  4713.     // Infects (turns to bang-dynamite) all surrounding dynamite.
  4714.  
  4715.     for (xx = x - 1; xx <= x + 1; xx++)
  4716.     {   for (yy = y - 1; yy <= y + 1; yy++)
  4717.         {   if (valid(xx, yy))
  4718.             {   if (field[xx][yy] == DYNAMITE)
  4719.                 {   field[xx][yy] = TEMPBANGDYNAMITE;
  4720.                     worm[player].dynamitescore += POINTS_DYNAMITE;
  4721.                     infector[xx][yy] = player;
  4722. }   }   }   }   }
  4723.  
  4724. MODULE void octopusfire(UBYTE which)
  4725. {   UBYTE i;
  4726.     SBYTE x, y, deltax, deltay;
  4727.  
  4728.     for (i = 0; i <= CREATURES; i++)
  4729.     {   if (!creature[i].alive)
  4730.         {   switch(creature[which].dir)
  4731.             {
  4732.             case 0:
  4733.                 deltax = 0;
  4734.                 deltay = -1;
  4735.             break;
  4736.             case 1:
  4737.                 deltax = 1;
  4738.                 deltay = -1;
  4739.             break;
  4740.             case 2:
  4741.                 deltax = 1;
  4742.                 deltay = 0;
  4743.             break;
  4744.             case 3:
  4745.                 deltax = 1;
  4746.                 deltay = 1;
  4747.             break;
  4748.             case 4:
  4749.                 deltax = 0;
  4750.                 deltay = 1;
  4751.             break;
  4752.             case 5:
  4753.                 deltax = -1;
  4754.                 deltay = 1;
  4755.             break;
  4756.             case 6:
  4757.                 deltax = -1;
  4758.                 deltay = 0;
  4759.             break;
  4760.             case 7:
  4761.                 deltax = -1;
  4762.                 deltay = -1;
  4763.             break;
  4764.             default:
  4765.             break;
  4766.             }
  4767.             x = creature[which].x + deltax;
  4768.             y = creature[which].y + deltay;
  4769.             if (valid(x, y) && field[x][y] >= FIRSTEMPTY && field[x][y] <= LASTEMPTY)
  4770.             {   effect(FXGET_PULSE);
  4771.                 createcreature(FRAGMENT, i, x, y, deltax, deltay, 255);
  4772.                 goto out;
  4773.     }   }   }
  4774.  
  4775. out:
  4776.     if (++creature[which].dir == 8)
  4777.     {   creature[which].dir = -1;
  4778. }   }
  4779.  
  4780. MODULE void createcreature(UBYTE species,
  4781.                            UBYTE which,
  4782.                            SBYTE x,
  4783.                            SBYTE y,
  4784.                            SBYTE deltax,
  4785.                            SBYTE deltay,
  4786.                            UBYTE player)
  4787. {   switch(species)
  4788.     {
  4789.     case FRAGMENT:
  4790.         creature[which].speed    = SPEED_FRAGMENT;
  4791.         creature[which].score    = SCORE_FRAGMENT;
  4792.         creature[which].hardness = HARDNESS_FRAGMENT;
  4793.         creature[which].visible  = TRUE;
  4794.         creature[which].last     = EMPTY;
  4795.         creature[which].type     = 255;
  4796.         change(x, y, FRAGMENT);
  4797.     break;
  4798.     case OCTOPUS:
  4799.         creature[which].speed    = SPEED_OCTOPUS;
  4800.         creature[which].score    = SCORE_OCTOPUS;
  4801.         creature[which].hardness = HARDNESS_OCTOPUS;
  4802.         creature[which].visible  = TRUE;
  4803.         creature[which].last     = field[x][y];
  4804.         creature[which].dir      = -1;
  4805.         creature[which].type     = 255;
  4806.         change(x, y, OCTOPUS);
  4807.     break;
  4808.     case FISH:
  4809.         creature[which].speed    = SPEED_FISH;
  4810.         creature[which].score    = SCORE_FISH;
  4811.         creature[which].hardness = HARDNESS_FISH;
  4812.         creature[which].visible  = TRUE;
  4813.         creature[which].last     =
  4814.         creature[which].oldlast  = field[x][y];
  4815.         creature[which].type     = 255;
  4816.         change(x, y, FISH);
  4817.     break;
  4818.     case GOAT:
  4819.         effect(FXBORN_GOAT);
  4820.         creature[which].speed    = SPEED_GOAT;
  4821.         creature[which].score    = SCORE_GOAT;
  4822.         creature[which].hardness = HARDNESS_GOAT;
  4823.         creature[which].visible  = TRUE;
  4824.         creature[which].last     =
  4825.         creature[which].oldlast  = field[x][y];
  4826.         creature[which].type     = 255;
  4827.         change(x, y, GOAT);
  4828.     break;
  4829.     case DOG:
  4830.         creature[which].speed    = SPEED_DOG;
  4831.         creature[which].score    = SCORE_DOG;
  4832.         creature[which].hardness = HARDNESS_DOG;
  4833.         creature[which].visible  = TRUE;
  4834.         creature[which].last     = EMPTY;
  4835.         creature[which].pos      = -1;
  4836.         creature[which].dormant  = DORMANT; /* dormant */
  4837.         creature[which].type     = 255;
  4838.         field[x][y] = DOG;
  4839.         draw(x, y, DOGDORMANT);
  4840.     break;
  4841.     case ORB:
  4842.         effect(FXBORN_ORB);
  4843.         creature[which].speed    = SPEED_ORB;
  4844.         creature[which].score    = SCORE_ORB;
  4845.         creature[which].hardness = HARDNESS_ORB;
  4846.         creature[which].visible  = TRUE;
  4847.         creature[which].last     = EMPTY;
  4848.         creature[which].multi    = 1;
  4849.         creature[which].type     = 255;
  4850.         change(x, y, ORB);
  4851.     break;
  4852.     case CLOUD:
  4853.         creature[which].speed    = SPEED_CLOUD;
  4854.         creature[which].score    = SCORE_CLOUD;
  4855.         creature[which].hardness = HARDNESS_CLOUD;
  4856.         creature[which].visible  = TRUE;
  4857.         creature[which].last     = EMPTY;
  4858.         creature[which].type     = 255;
  4859.         change(x, y, CLOUD);
  4860.     break;
  4861.     case PENGUIN:
  4862.         effect(FXBORN_PENGUIN);
  4863.         creature[which].speed    = SPEED_PENGUIN;
  4864.         creature[which].score    = SCORE_PENGUIN;
  4865.         creature[which].hardness = HARDNESS_PENGUIN;
  4866.         creature[which].visible  = TRUE;
  4867.         creature[which].last     = EMPTY;
  4868.         creature[which].type     = 255;
  4869.         change(x, y, PENGUIN);
  4870.     break;
  4871.     case TIMEBOMB:
  4872.         creature[which].speed    = SPEED_TIMEBOMB;
  4873.         creature[which].score    = SCORE_TIMEBOMB;
  4874.         creature[which].hardness = HARDNESS_TIMEBOMB;
  4875.         creature[which].last     = EMPTY;
  4876.         creature[which].time     = 10;
  4877.         creature[which].visible  = TRUE;
  4878.         creature[which].type     = 255;
  4879.         field[x][y] = TIMEBOMB;
  4880.         draw(x, y, ZERO + 9);
  4881.     break;
  4882.     case DRIP:
  4883.         effect(FXBORN_DRIP);
  4884.         creature[which].speed    = SPEED_DRIP;
  4885.         creature[which].score    = SCORE_DRIP;
  4886.         creature[which].hardness = HARDNESS_DRIP;
  4887.         creature[which].last     = EMPTY;
  4888.         creature[which].type     = player;
  4889.         creature[which].visible  = TRUE;
  4890.         change(x, y, FIRSTDRIP + creature[which].type);
  4891.     break;
  4892.     case WHIRLWIND:
  4893.         effect(FXGET_CYCLONE);
  4894.         creature[which].speed    = SPEED_WHIRLWIND;
  4895.         creature[which].score    = SCORE_WHIRLWIND;
  4896.         creature[which].hardness = HARDNESS_WHIRLWIND;
  4897.         creature[which].last     = EMPTY;
  4898.         creature[which].visible  = TRUE;
  4899.         creature[which].type     = 255;
  4900.         change(x, y, WHIRLWIND);
  4901.     break;
  4902.     case MISSILE:
  4903.         effect(FXBORN_MISSILE);
  4904.         creature[which].score    = SCORE_MISSILE;
  4905.         creature[which].speed    = SPEED_MISSILE;
  4906.         creature[which].hardness = HARDNESS_MISSILE;
  4907.         creature[which].visible  = FALSE;
  4908.         creature[which].last     = EMPTY;
  4909.         creature[which].type     = player;
  4910.         creature[which].frame    = 0;
  4911.     break;
  4912.     case BIRD:
  4913.         creature[which].speed    = SPEED_BIRD;
  4914.         creature[which].score    = SCORE_BIRD;
  4915.         creature[which].hardness = HARDNESS_BIRD;
  4916.         creature[which].visible  = TRUE;
  4917.         creature[which].last     = EMPTY;
  4918.         creature[which].frame    = 0;
  4919.         creature[which].dir      = 1;
  4920.         creature[which].type     = 255;
  4921.         change(x, y, BIRD);
  4922.     break;
  4923.     case OTTER:
  4924.         creature[which].speed    = SPEED_OTTER;
  4925.         creature[which].score    = SCORE_OTTER;
  4926.         creature[which].hardness = HARDNESS_OTTER;
  4927.         creature[which].visible  = TRUE;
  4928.         creature[which].last     = STONE; // should really check whether it should be dynamite instead
  4929.         creature[which].type     = 255;
  4930.         if (x == 0)
  4931.         {   creature[which].going    = OTTER_DOWN;
  4932.             creature[which].journey  = OTTER_RIGHT;
  4933.         } else
  4934.         {   creature[which].going    = OTTER_UP;
  4935.             creature[which].journey  = OTTER_LEFT;
  4936.         }
  4937.         field[x][y] = OTTER;
  4938.         draw(x, y, OTTER);
  4939.     break;
  4940.     case GIRAFFE:
  4941.         creature[which].speed    = SPEED_GIRAFFE;
  4942.         creature[which].score    = SCORE_GIRAFFE;
  4943.         creature[which].hardness = HARDNESS_GIRAFFE;
  4944.         creature[which].visible  = TRUE;
  4945.         creature[which].type     = 255;
  4946.         change(x, y, GIRAFFE);
  4947.     break;
  4948.     case LION:
  4949.         creature[which].speed    = SPEED_LION;
  4950.         creature[which].score    = SCORE_LION;
  4951.         creature[which].hardness = HARDNESS_LION;
  4952.         creature[which].visible  = TRUE;
  4953.         creature[which].type     = 255;
  4954.         change(x, y, LION);
  4955.     break;
  4956.     default:
  4957.     break;
  4958.     }
  4959.  
  4960.     if (level > 5 && creature[which].speed >= 2)
  4961.         creature[which].speed--;
  4962.     if (level > 10 && creature[which].speed >= 2)
  4963.         creature[which].speed--;
  4964.     if (level > 20 && creature[which].speed >= 2)
  4965.         creature[which].speed--;
  4966.  
  4967.     creature[which].alive   = TRUE;
  4968.     creature[which].x       = x;
  4969.     creature[which].y       = y;
  4970.     creature[which].deltax  = deltax;
  4971.     creature[which].deltay  = deltay;
  4972.     creature[which].species = species;
  4973. }
  4974.  
  4975. MODULE ULONG arand(ULONG number)
  4976. {   // Returns a value between 0 and number, inclusive.
  4977.  
  4978.     return((ULONG) (rand() % (number + 1)));
  4979. }
  4980.  
  4981. MODULE void protcreature(UBYTE player, UBYTE which)
  4982. {   UBYTE i;
  4983.  
  4984.     /* Handles collisions between protectors and creatures. */
  4985.  
  4986.     switch(creature[which].species)
  4987.     {
  4988.     case BIRD:
  4989.     case CLOUD:
  4990.     case DOG:
  4991.     case DRIP:
  4992.     case ORB:
  4993.     case PENGUIN:
  4994.         effect(FXUSE_PROTECTOR);
  4995.         wormkillcreature(player, which);
  4996.     break;
  4997.     case FRAGMENT:
  4998.         effect(FXUSE_PROTECTOR);
  4999.         reflect(which);
  5000.     break;
  5001.     case MISSILE:
  5002.         if (player != creature[which].type)
  5003.         {   effect(FXUSE_PROTECTOR);
  5004.             wormkillcreature(player, which);
  5005.         } else creature[which].visible = FALSE;
  5006.     break;
  5007.     case WHIRLWIND:
  5008.         for (i = 0; i <= PROTECTORS; i++)
  5009.         {   if
  5010.             (   protector[player][i].alive
  5011.              && protector[player][i].x == creature[which].x
  5012.              && protector[player][i].y == creature[which].y
  5013.             )
  5014.             {   protector[player][i].alive = FALSE;
  5015.         }   }
  5016.     break;
  5017.     default:
  5018.     break;
  5019. }   }
  5020.  
  5021. MODULE void wormcreature(UBYTE player, UBYTE which)
  5022. {   SBYTE newx, newy;
  5023.  
  5024.     /* Handles collisions between worms and creatures. */
  5025.  
  5026.     switch(creature[which].species)
  5027.     {
  5028.     case CLOUD:
  5029.         wormkillcreature(player, which);
  5030.         if (worm[player].armour == 0)
  5031.         {   worm[player].alive = FALSE;
  5032.             worm[player].cause = CLOUD;
  5033.             worm[player].victor = -1;
  5034.         }
  5035.     break;
  5036.     case DOG:
  5037.         if (creature[which].dormant == DORMANT)
  5038.         {   effect(FXBORN_DOG);
  5039.             creature[which].dormant = AWAKENING;
  5040.             creature[which].type    = player;
  5041.             worm[player].last       = DOG;
  5042.         } else
  5043.         {   wormkillcreature(player, which);
  5044.             if (worm[player].armour == 0)
  5045.             {   worm[player].alive  = FALSE;
  5046.                 worm[player].cause  = DOG;
  5047.                 worm[player].victor = -1;
  5048.         }   }
  5049.     break;
  5050.     case DRIP:
  5051.         wormkillcreature(player, which);
  5052.         if (player != creature[which].type && worm[player].armour == 0)
  5053.         {   worm[player].alive  = FALSE;
  5054.             worm[player].cause  = FIRSTDRIP + creature[which].type;
  5055.             worm[player].victor = -1;
  5056.         }
  5057.     break;
  5058.     case LION:
  5059.     case FISH:
  5060.     case GOAT:
  5061.     case OCTOPUS:
  5062.         worm[player].alive  = FALSE;
  5063.         worm[player].cause  = creature[which].species;
  5064.         worm[player].victor = -1;
  5065.     break;
  5066.     case FRAGMENT:
  5067.         if (worm[player].armour > 0)
  5068.         {   effect(FXUSE_ARMOUR);
  5069.             reflect(which);
  5070.         } else
  5071.         {   wormkillcreature(player, which);
  5072.             worm[player].cause  = FRAGMENT;
  5073.             worm[player].victor = -1;
  5074.             worm[player].alive  = FALSE;
  5075.         }
  5076.     break;
  5077.     case GIRAFFE:
  5078.         newx = worm[player].x - (worm[player].deltax * DISTANCE_GIRAFFE);
  5079.         newy = worm[player].y - (worm[player].deltay * DISTANCE_GIRAFFE);
  5080.  
  5081.         if
  5082.         (   valid(newx, newy)
  5083.          && field[newx][newy] != METAL
  5084.          && field[newx][newy] != STONE
  5085.          && field[newx][newy] != WOOD
  5086.          && field[newx][newy] != TELEPORT
  5087.         )
  5088.         {   worm[player].deltax = -worm[player].deltax;
  5089.             worm[player].deltay = -worm[player].deltay;
  5090.             worm[player].x = newx;
  5091.             worm[player].y = newy;
  5092.         } else
  5093.         {   worm[player].alive  = FALSE;
  5094.             worm[player].cause  = GIRAFFE;
  5095.             worm[player].victor = -1;
  5096.         }
  5097.     break;
  5098.     case MISSILE:
  5099.         if (creature[which].type == player)
  5100.         {   creature[which].visible = FALSE;
  5101.         } else
  5102.         {   wormkillcreature(player, which);
  5103.             if (worm[player].armour == 0)
  5104.             {   worm[player].cause  = FIRSTMISSILE + creature[which].type;
  5105.                 worm[player].victor = creature[which].type;
  5106.                 worm[player].alive  = FALSE;
  5107.             } else effect(FXUSE_ARMOUR);
  5108.         }
  5109.     break;
  5110.     case BIRD:
  5111.     case PENGUIN:
  5112.     case ORB:
  5113.         wormkillcreature(player, which);
  5114.         if (worm[player].armour > 0)
  5115.         {   effect(FXUSE_ARMOUR);
  5116.         } else
  5117.         {   worm[player].cause = creature[which].species;
  5118.             worm[player].victor = -1;
  5119.             worm[player].alive = FALSE;
  5120.         }
  5121.     break;
  5122.     case WHIRLWIND:
  5123.         worm[player].cause  = WHIRLWIND;
  5124.         worm[player].victor = -1;
  5125.         worm[player].alive  = FALSE;
  5126.     break;
  5127.     default:
  5128.     break;
  5129. }   }
  5130.  
  5131. MODULE void creaturecreature(UBYTE which1, UBYTE which2)
  5132. {   if (creature[which1].hardness > creature[which2].hardness)
  5133.     {   creature[which2].alive = FALSE;
  5134.         if (creature[which1].species == MISSILE)
  5135.         {   wormkillcreature(creature[which1].type, which2);
  5136.     }   }
  5137.     elif (creature[which1].hardness < creature[which2].hardness)
  5138.     {   creature[which1].alive = FALSE;
  5139.         if (creature[which2].species == MISSILE)
  5140.         {   wormkillcreature(creature[which2].type, which1);
  5141.     }   }
  5142.     else
  5143.     {   creature[which1].alive =
  5144.         creature[which2].alive = FALSE;
  5145.         change(creature[which1].x, creature[which1].y, BONUS);
  5146. }   }
  5147.  
  5148. /* NAME     align -- right-justify a string within another string
  5149. SYNOPSIS    align(STRPTR, SBYTE, TEXT);
  5150. FUNCTION    Moves all text in a string to the right, padding with
  5151.             spaces. Does not itself add a null terminator.
  5152. INPUTS      string - pointer to the string of text
  5153.               size - size in characters of the containing string
  5154.             filler - what to pad the left of the string with
  5155. NOTE        Null terminators are written over by this function, but that
  5156.             does not matter, because calling functions use Text() with an
  5157.             explicit length. This function only works with monospaced
  5158.             fonts. */
  5159.  
  5160. AGLOBAL void align(STRPTR string, SBYTE size, TEXT filler)
  5161. {   SBYTE i, shift, length;
  5162.  
  5163.     length = strlen((const char*) string);
  5164.     shift = size - length;
  5165.     for (i = 1; i <= length; i++)
  5166.         *(string + size - i) = *(string + size - i - shift);
  5167.     for (i = 0; i <= shift - 1; i++)
  5168.         *(string + i) = filler;
  5169. }
  5170.  
  5171. MODULE void ReadGameports(void)
  5172. {   ReadStandardJoystick(0);
  5173.     ReadStandardJoystick(1);
  5174.     ReadAdapterJoystick(2);
  5175.     ReadAdapterJoystick(3);
  5176.     ReadGamepads();
  5177. }
  5178.  
  5179. MODULE void drawmissile(SBYTE x, SBYTE y, UBYTE which)
  5180. {   draw(x, y, missileframes[creature[which].type][creature[which].frame]);
  5181. }
  5182.  
  5183. MODULE void checkrectangle(SBYTE direction, SBYTE player, SBYTE horizontalsize, SBYTE verticalsize)
  5184. {   AUTO SBYTE i, x, y, leftx, rightx, topy, bottomy;
  5185.     AUTO UBYTE c;
  5186.     PERSIST struct
  5187.     {   SBYTE deltax[4], deltay[4];
  5188.     } deltas[4] =
  5189.     { { { 0, -1,  0,  1}, // northwest
  5190.         {-1,  0,  1,  0}
  5191.       },
  5192.       { { 0,  1,  0, -1}, // northeast
  5193.         {-1,  0,  1,  0}
  5194.       },
  5195.       { { 0,  1,  0, -1}, // southeast
  5196.         { 1,  0, -1,  0}
  5197.       },
  5198.       { { 0, -1,  0,  1}, // southwest
  5199.         { 1,  0, -1,  0}
  5200.     } };
  5201.     PERSIST struct
  5202.     {   SBYTE leftx, rightx, topy, bottomy;
  5203.     } enclose[4] =
  5204.     { {-127,   -1, -127,  -1 }, // northwest
  5205.       {   1,  127, -127,  -1 }, // northeast
  5206.       {   1,  127,    1, 127 }, // southeast
  5207.       {-127,   -1,    1, 127 }  // southwest
  5208.     };
  5209.  
  5210.     x = worm[player].x;
  5211.     y = worm[player].y; // for speed
  5212.  
  5213.     for (i = 0; i <= verticalsize; i++)
  5214.     {   x += deltas[direction].deltax[0];
  5215.         y += deltas[direction].deltay[0];
  5216.         if ((!valid(x, y)) || field[x][y] != FIRSTTAIL + player)
  5217.         {   return;
  5218.     }   }
  5219.     for (i = 0; i <= horizontalsize; i++)
  5220.     {   x += deltas[direction].deltax[1];
  5221.         y += deltas[direction].deltay[1];
  5222.         if ((!valid(x, y)) || field[x][y] != FIRSTTAIL + player)
  5223.         {   return;
  5224.     }   }
  5225.     for (i = 0; i <= verticalsize; i++)
  5226.     {   x += deltas[direction].deltax[2];
  5227.         y += deltas[direction].deltay[2];
  5228.         if ((!valid(x, y)) || field[x][y] != FIRSTTAIL + player)
  5229.         {   return;
  5230.     }   }
  5231.     for (i = 0; i <= horizontalsize - 1; i++)
  5232.     {   x += deltas[direction].deltax[3];
  5233.         y += deltas[direction].deltay[3];
  5234.         if ((!valid(x, y)) || field[x][y] != FIRSTTAIL + player)
  5235.         {   return;
  5236.     }   }
  5237.  
  5238.     effect(FXDO_ENCLOSE);
  5239.     enclosed = TRUE;
  5240.     if (enclose[direction].leftx < -1)
  5241.         enclose[direction].leftx = -horizontalsize;
  5242.     elif (enclose[direction].leftx > 1)
  5243.         enclose[direction].leftx = horizontalsize + 1;
  5244.     if (enclose[direction].rightx < -1)
  5245.         enclose[direction].rightx = -(horizontalsize + 1);
  5246.     elif (enclose[direction].rightx > 1)
  5247.         enclose[direction].rightx = horizontalsize;
  5248.     if (enclose[direction].topy < -1)
  5249.         enclose[direction].topy = -verticalsize;
  5250.     elif (enclose[direction].topy > 1)
  5251.         enclose[direction].topy = verticalsize + 1;
  5252.     if (enclose[direction].bottomy < -1)
  5253.         enclose[direction].bottomy = -(verticalsize + 1);
  5254.     elif (enclose[direction].bottomy > 1)
  5255.         enclose[direction].bottomy = verticalsize;
  5256.  
  5257.       leftx = worm[player].x + enclose[direction].leftx;
  5258.      rightx = worm[player].x + enclose[direction].rightx;
  5259.        topy = worm[player].y + enclose[direction].topy;
  5260.     bottomy = worm[player].y + enclose[direction].bottomy;
  5261.     // assert(leftx >= 0 && rightx <= FIELDX && topy >= 0 && bottomy <= FIELDY && leftx < rightx && topy < bottomy);
  5262.  
  5263.     for (x = leftx; x <= rightx; x++)
  5264.     {   for (y = topy; y <= bottomy; y++)
  5265.         {   c = field[x][y];
  5266.             if
  5267.             (    (c >= FIRSTEMPTY && c <= LASTEMPTY)
  5268.              || ((c >= FIRSTTAIL  && c <= LASTTAIL ) && c != FIRSTTAIL + player)
  5269.              || ((c >= FIRSTGLOW  && c <= LASTGLOW ) && c != FIRSTGLOW + player)
  5270.             ) 
  5271.             {   change(x, y, FIRSTGLOW + player);
  5272.                 wormscore(player, POINTS_ENCLOSURE + POINTS_TURNGOLD);
  5273. }   }   }   }
  5274.  
  5275. MODULE void endoflevel(void)
  5276. {   SBYTE advancer,
  5277.           player;
  5278.     UWORD counter[4] = {0, 0, 0, 0};
  5279.     SBYTE x, y;
  5280.  
  5281.         for (player = 0; player <= 3; player++)
  5282.         {   if (worm[player].lives)
  5283.             {   for (x = 0; x <= FIELDX; x++)
  5284.                 {   for (y = 0; y <= FIELDY; y++)
  5285.                     {   if (field[x][y] == FIRSTTAIL + player || field[x][y] == FIRSTGLOW + player)
  5286.                         {   counter[player]++;
  5287.         }   }   }   }   }
  5288.         if (counter[0] >= counter[1]
  5289.          && counter[0] >= counter[2]
  5290.          && counter[0] >= counter[3])
  5291.         {   advancer = 0;
  5292.         } elif (counter[1] >= counter[0]
  5293.          && counter[1] >= counter[2]
  5294.          && counter[1] >= counter[3])
  5295.         {   advancer = 1;
  5296.         } elif (counter[2] >= counter[0]
  5297.          && counter[2] >= counter[1]
  5298.          && counter[2] >= counter[3])
  5299.         {   advancer = 2;
  5300.         } else
  5301.         {   advancer = 3;
  5302.         }
  5303.  
  5304.     if (level++ == 0)
  5305.     {   level = reallevel + 1;
  5306.         reallevel = 0;
  5307.     }
  5308.     stopfx();
  5309.     if (level > levels)
  5310.     {   effect(FXCELEBRATE);
  5311.     }
  5312.     newlevel(advancer);
  5313. }
  5314.  
  5315. MODULE FLAG getnumber(SBYTE player)
  5316. {   /* This function returns TRUE if the final number (ie. 9) was gotten,
  5317.     otherwise FALSE.
  5318.  
  5319.     The calling function is responsible for calling putnumber() if it
  5320.     wants a new number to appear. */
  5321.  
  5322.     wormscore(player, POINTS_LETTER * number);
  5323.     worm[player].numbers++;
  5324.     number++;
  5325.  
  5326.     if (number == 10)
  5327.     {   endoflevel();
  5328.         return(TRUE);
  5329.     }
  5330.     return(FALSE);
  5331. }
  5332.